/*
* This file is part of Caliph & Emir.
*
* Caliph & Emir 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.
*
* Caliph & Emir 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 Caliph & Emir; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright statement:
* --------------------
* (c) 2005 by Werner Klieber (werner@klieber.info)
* http://caliph-emir.sourceforge.net
*/
package at.wklieber.gui;
import at.wklieber.Settings;
import at.wklieber.tools.Console;
import at.wklieber.tools.IAccessFile;
import at.wklieber.tools.Java2dTools;
import at.wklieber.tools.MessageBox;
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
public class IDrawPanel
//extends JScrollPane
extends JPanel
implements MouseListener, MouseMotionListener, DropTargetListener {
private static java.util.logging.Logger cat = java.util.logging.Logger.getLogger(IDrawPanel.class.getName());
private static Console console = Console.getReference();
private static Settings cfg = Settings.getReference();
private static Java2dTools java2dTools = Java2dTools.getReference();
private static IAccessFile config = cfg.getConfigAccess();
private static final int DEFAULT_SHAPE_SIZE = 150;
public static final int DROP_ACCECPT_ALL = 0;
public static final int DROP_ACCECPT_IMAGES = 1; // use in the draw by sketch area
public static final int DROP_ACCECPT_REPRESENTANTS = 2; // use in the mainframe
private DropTarget dropTarget = null;
private int acceptDropTargets = DROP_ACCECPT_ALL;
// if true, the panel is used to draw Mulmiedia objects and operator
// this means, when deleting objects, the previous operator (ILine) is removed too
private boolean isMathMode = false;
// contains a method that is called when a new compoent is dropped
// to this drawPanel
private IComponentReceivedInterface parentFrame = null;
private BufferedImage backgroundImage = null;
private Rectangle backgroundImageSize = null;
private boolean acceptDnd = true; // if false, all dnd sources are not allowed
public IDrawPanel() {
init(null);
}
public IDrawPanel(IComponentReceivedInterface parentFrame1) {
init(parentFrame1);
}
private void init(IComponentReceivedInterface parentFrame1) {
parentFrame = parentFrame1;
isMathMode = false;
//--------- dnd trop stuff
dropTarget = new DropTarget((Component) this, (int) DnDConstants.ACTION_COPY,
(DropTargetListener) this, true);
dropTarget.setActive(true);
this.setDropTarget(dropTarget);
validate();
}
public boolean isAcceptDnd() {
return acceptDnd;
}
public void setAcceptDnd(boolean acceptDnd) {
this.acceptDnd = acceptDnd;
}
public int getAcceptDropTargets() {
return acceptDropTargets;
}
public void setAcceptDropTargets(int acceptDropTargets) {
this.acceptDropTargets = acceptDropTargets;
}
/**
* returns the number of ILines in the drawpanel.
* Note: all ILines must be at the and of the component-list (so they are painted first);
*/
public int getILineComponentsCount() {
int returnValue = 0;
try {
Component[] comps = this.getComponents();
int counter = comps.length - 1;
while ((counter > -1) && (ILine.class.isInstance(comps[counter]))) {
returnValue++;
counter--;
}
} catch (Exception e) {
cat.severe(e.toString());
}
return returnValue;
}
/*public void setObjectPalette(ObjectPalette objectPalette) {
this.objectPalette = objectPalette;
}*/
// not prepared to add lines
public void addNewComponent(IComponent component1) {
//this.add(component1, 0);
this.add(component1);
//this.add(component1, this.getComponents().length);
component1.setDrawPanel((JPanel) this);
component1.addMouseListener(component1);
component1.addMouseMotionListener(component1);
}
/**
* dnd drop target stuff. Supported types are Images and Java-Icomponents (internul stuff).
* Supported is Windows with Internet Explorer and Mozilla
*
* @param dtde
*/
public void drop(DropTargetDropEvent dtde) {
try {
if (!acceptDnd) {
dtde.rejectDrop();
return;
}
//cat.fine("dnd dropped, included Flavors:");
Transferable t = dtde.getTransferable();
DataFlavor[] flavorList = dtde.getCurrentDataFlavors();
/*
for (int i = 0; i < flavorList.length; i++) {
cat.fine("--> Dnd Transfer Mime-Type: <" + flavorList[i].getMimeType() + ">, Info <" + flavorList[i].toString() + ">");
}
*/
/*
cat.fine("TransferList");
DataFlavor[] flavorListD = t.getTransferDataFlavors();
for (int i = 0; i < flavorListD.length; i++) {
cat.fine("--> Dnd Transfer Mime-Type: <" + flavorListD[i].getMimeType() + ">, Info <" + flavorListD[i].toString() + ">");
}
*/
IComponent component = null; //this object will receive the dropped data
String urlString = ""; // set this to the image name to request metadat for search results
URL imageUrl = null; // for downloading images in ie
//------------- ACCEPT own IComponent Data ----------------------------
if (t.isDataFlavorSupported(IComponentTransferable.localIComponentFlavor)) {
cat.info("Got IComponent from Objectpalette");
dtde.acceptDrop(DnDConstants.ACTION_COPY);
component = (IComponent) t.getTransferData(IComponentTransferable.localIComponentFlavor);
dtde.getDropTargetContext().dropComplete(true);
boolean accept = true;
String errorMessage = "";
if (acceptDropTargets == DROP_ACCECPT_REPRESENTANTS) {
// it is the panel of the mainframe - we do only accept images and IRepresentants
String name = component.getClass().getName();
//System.out.println(name);
if (!(IImageComponent.class.getName().equals(name))) {
accept = false;
errorMessage = "This kind of object cannot be dropped into his screen. \n " +
"Please use an image or a Representant";
}
}
// TODO: add here restrictions for the "draw by sketch" dialog
if (!accept) {
MessageBox.displayMessage("Error: invalid object", errorMessage);
dtde.getDropTargetContext().dropComplete(true);
return; // ----------------> EXIT POINT <--------------------------------------
}
// prepare for default output in parent
if (IImageComponent.class.isInstance(component)) {
IImageComponent c = (IImageComponent) component;
if (c.getImage() == null) cat.severe("Image is null");
}
if (IColorRectangle.class.isInstance(component)) {
IColorRectangle c = (IColorRectangle) component;
c.setDoDisplayPercentage(true);
} else if (IShape.class.isInstance(component)) {
IShape c = (IShape) component;
//c.setMoveable(true);
//c.setResizeable(true);
///c.setDoDnd(false);
c.setDrawDots(true);
c.setComponentBounds(0, 0, DEFAULT_SHAPE_SIZE, DEFAULT_SHAPE_SIZE);
}
//--------------------- get as much data as possible from standard flavors ------
} else {
// tested for internet explorer (not working in all cases) and mozilla (working)
boolean accept = false;
BufferedImage bImage = null;
String dropString = "";
if (t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
cat.info("get IMAGE from imageFlavor directly");
dtde.acceptDrop(DnDConstants.ACTION_COPY);
Image image = (Image) t.getTransferData(DataFlavor.imageFlavor);
if (image != null) {
bImage = java2dTools.imageToBufferedImage(image);
}
cat.fine("DnD Target: Image received received");
accept = true;
// get the image url for further
if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
cat.info("get URL from stringFlavor directly");
String dummy = (String) t.getTransferData(DataFlavor.stringFlavor);
if (dummy != null && dummy.length() > 0) {
urlString = dummy;
cat.fine("Image URL: <" + urlString + ">");
}
} else { // try to get the url from something else: does not work
/*
for (int i = 0; i < flavorList.length; i++) {
DataFlavor x = flavorList[i];
if (x.isFlavorTextType()) {
String data = "";
Object q = t.getTransferData(x);
data = q.getClass().getName();
System.out.println("DATA: <" + data + ">");
if (String.class.isInstance(q)) {
String res = (String) q;
data = "String: <" + res + ">";
System.out.println(data);
}
if (java.io.InputStreamReader.class.isInstance(q)) {
InputStreamReader res = (InputStreamReader) q;
data = MiscTools.inputStreamToString(res, "");
data = "InputStreamReader: <" + data + ">";
System.out.println(data);
}
}
} // end for
*/
}
} // end if is imageflavor
// try to get the image url
for (int i = 0; i < flavorList.length; i++) {
DataFlavor flavor = flavorList[i];
if (flavor.getRepresentationClass().equals(java.net.URL.class)) {
try {
if (dtde.isDataFlavorSupported(flavor)) {
if (!accept) {
dtde.acceptDrop(DnDConstants.ACTION_COPY);
accept = true;
}
URL myUrl = (URL) dtde.getTransferable().getTransferData(flavor);
cat.fine("DnD Target: URL received, null: " + (myUrl == null));
if (myUrl != null) {
imageUrl = myUrl;
}
//outputArea.append("\tURL: " + myUrl.toString() + "\n");
break;
}
} catch (Exception e) {
cat.fine("unable to get The URL of the image. (Mozill causes this exception)");
//e.printStackTrace();
}
}
} // end for
//} // end if imageFlavor
// ie just sends the string, so we have load it
if ((bImage == null) && (imageUrl != null)) {
/*
URL url = null;
try {
url = new URL(imageUrl);
} catch (MalformedURLException e) {
//e.printStackTrace();
cat.severe(e.toString());
}
*/
// Get the image
if (imageUrl != null) {
cat.info("load image from url: " + imageUrl.toExternalForm());
Image image = Toolkit.getDefaultToolkit().createImage(imageUrl);
if (image != null) {
bImage = java2dTools.imageToBufferedImage(image);
}
}
}
component = new IImageComponent(this, bImage);
if (!accept) {
cat.fine("Flavor rejected");
dtde.rejectDrop();
}
} // end if what flavor
dtde.getDropTargetContext().dropComplete(true);
//----- Now we have all the data
if (component != null) {
Point point = dtde.getLocation();
component.setDrawPanel((JPanel) this);
component.setComponentLocation(point);
component.setDoDnd(false);
component.setResizeable(true);
component.setMoveable(true);
if (parentFrame == null) { // draw it if no listener. Otherwise the listener gets the data and can do what it wants
addNewComponent(component);
repaint();
//addImage(image.getImage(), (int) point.getX(), (int) point.getY());
} else {
parentFrame.getIcomponentFromDnd(component);
}
repaint();
if (imageUrl != null) {
urlString = imageUrl.toExternalForm();
}
cat.fine("URL: <" + urlString + ">");
if (urlString.length() > 0) {
String id = ""; // id to load mpeg7 data if needed
String fileId = "";
try {
//String urlPath = FileTools.getFilePath(urlString);
// get the filename without the ending ".jpg"
// Url is e.g: http://129.27.200.42:8082/cocoon/imb2/image.jsp?id=jr_test;IMB;1;T00:01:23:19F25
int start = urlString.indexOf('=');
String subString = urlString.substring(start + 1);
// remove eventuell ending stuff
start = subString.indexOf("\n");
if (start > 0) {
fileId = subString.substring(0, start);
} else
fileId = subString;
//fileId = urlString.substring(urlPath.length() - 1, urlString.length() - 4);
id = "";
} catch (Exception e) {
// make no furhter request on an failure
e.printStackTrace();
cat.severe(e.toString());
}
if (id.length() != 0) {
//MessageBox.displayMessage("", "");
//todo: add here the code to parse the mpeg7 file when retrieving a search result
//parseMpeg7Document(fileId);
}
} // end if get further metadata
} // endif got a valid image
// for debugging
//parseMpeg7Document("jr_test;IMB;1;");
//{ Must catch IOException and UnsupportedFlavorException
} catch (Exception e) {
cat.severe(e.toString());
e.printStackTrace();
}
}
/*private void parseMpeg7Document(String fileId) {
cat.fine("get MPEG7 file: <" + fileId + ">");
//http://129.27.200.42:8082/cocoon/imb2/query-xml-xml
//----- get the url from where to request the data
String relQueryPoint = config.getProperty("imbConfig/broker/webAccess/mpeg7Url", "",
"/cocoon/imb2/detail");
String webServerBaseUrl = config.getProperty("imbConfig/broker/webAccess/baseUrl", "",
"http://127.0.0.1:80");
String webUrl = webServerBaseUrl + relQueryPoint + "?id=" + fileId;
cat.fine("Complete url: <" + webUrl + ">");
// open an httprequest to that url
DownloadGuiThread thread = new DownloadGuiThread(webUrl);
thread.start(); // show message box and lock gui
//String result = thread.getResult();
//thread.close();
//thread = null;
String result = MiscTools.downloadTextFileFromHttp(webUrl, "");
thread.close(); // unlock gui
thread = null;
XmlTemplate temp = new XmlTemplate();
temp.setDocument(result);
Document doc = temp.getDocument(new Document(new Element("empty")));
//XMLTreeView view = new XMLTreeView(new JFrame(), true, doc);
//view.setSize(640, 480);
//view.setLocation(this.getLocation().x + 20, this.getLocation().y + 20);
//view.setVisible(true);
if (parentFrame != null) {
Controller controller = parentFrame.getController();
List dataList = controller.loadMpeg7FromXml(doc);
drawRepresentants(dataList);
}
//return "not implemented";
}*/
public BufferedImage getBackgroundImage() {
return backgroundImage;
}
public Rectangle getBackgroundImageSize() {
return backgroundImageSize;
}
public void setBackgroundImageSize(Rectangle backgroundImageSize) {
this.backgroundImageSize = backgroundImageSize;
}
public void setBackgroundImage(BufferedImage backgroundImage1) {
backgroundImage = java2dTools.getBrighterImage(backgroundImage1);
// backgroundImageSize is set in drawComponent
//backgroundImage = backgroundImage1;
cat.fine("set new brighter image as background");
//java2dTools.showImage(backgroundImage1);
validate();
repaint();
}
public void dragEnter(DropTargetDragEvent event) {
//cat.fine( "dtlistener dragEnter");
}
public void dragOver(DropTargetDragEvent event) {
//cat.fine( "dtlistener dragOver");
}
public void dropActionChanged(DropTargetDragEvent event) {
//cat.fine( "dtlistener dropActionChanged");
}
public void dragExit(DropTargetEvent event) {
//cat.fine( "dtlistener dragExit");
}
public String toString() {
return "nothing to report";
}
protected void finalize() throws Throwable {
super.finalize();
}
public void mouseClicked(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//cat.fine("repain panel for " + parentFrame);
// draw the background image
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (backgroundImage != null) {
Graphics2D g2 = (Graphics2D) g;
//cat.fine("Drawing Background");
//g2.clearRect(0, 0, this.getWidth(), this.getHeight());
Rectangle boundary;
boundary = (Rectangle) java2dTools.fitToWindow(this.getBounds(),
new Rectangle(0, 0, backgroundImage.getWidth(), backgroundImage.getHeight()));
//cat.fine("Drawing " + boundary.toString());
backgroundImageSize = new Rectangle((int) boundary.getX(), (int) boundary.getY(),
(int) boundary.getWidth(), (int) boundary.getHeight());
g2.drawImage(backgroundImage, backgroundImageSize.x, backgroundImageSize.y,
backgroundImageSize.width, backgroundImageSize.height, Color.WHITE, null);
} else {
backgroundImageSize = null;
}
//java2dTools.showImage(backgroundImage);
}
/**
* remove a component from the drawpanel and reset the search-opeartor component correctly
*
* @param a_component
*/
public void removeIComponent(IComponent a_component) {
if (!isMathMode) {
remove(a_component);
return; //------------------ EXIT POINT -----------------------
}
List<IComponentStruct> comps = getIComponents();
int pos = getComponentPosition(comps, a_component);
assert(pos >= 0);
if (pos == 0) {
remove(a_component);
if (comps.size() > 1) {
remove(comps.get(1).getComponent());
}
} else {
IComponentStruct thisComponent = comps.get(pos);
assert(!thisComponent.isOperator()); // operators are deleted automatically
IComponentStruct perviousOperator = comps.get(pos - 1);
assert(perviousOperator.isOperator());
IComponentStruct lastComponent = comps.get(pos - 2);
assert(!lastComponent.isOperator());
IComponentStruct nextOperator = null;
if (pos < (comps.size() - 1)) {
nextOperator = comps.get(pos + 1);
assert(nextOperator.isOperator());
}
// delete component and its previous operator
remove(perviousOperator.getComponent());
remove(thisComponent.getComponent());
// set next operatro to the previous component if available
if (nextOperator != null) {
ILine op = (ILine) nextOperator.getComponent();
IComponent p1 = op.getParentComponent01();
IComponent p2 = op.getParentComponent02();
IComponent newP = lastComponent.getComponent();
if (newP == p1) {
p2 = newP;
} else {
p1 = newP;
}
op.setParentComponent01(p1);
op.setParentComponent02(p2);
}
}
layoutComponents(null);
}
private int getComponentPosition(List<IComponentStruct> comps, IComponent a_component) {
int pos = -1;
for (int i = 0; i < comps.size(); i++) {
IComponentStruct struct = comps.get(i);
if (struct.equals(a_component)) {
pos = i;
break;
}
}
return pos;
}
/**
* auto layout the componenst in the drawpanel
*/
public void layoutComponents(Dimension aDefaultDimension) {
double w = this.getWidth();
double h = this.getHeight();
if (w == 0) {
w = aDefaultDimension.getWidth();
h = aDefaultDimension.getHeight();
}
if (h > 100) {
h = 100;
}
double ch = h * .9;
double cw = (h / 4) * 3;
double lineMin = 50;
double posX = 10;
double posY = (h - ch) / 2;
List<IComponentStruct> comps = getIComponents();
for (int i = 0; i < comps.size(); i++) {
IComponentStruct struct = comps.get(i);
if (!struct.isOperator()) {
IComponent comp = struct.getComponent();
if (i > 0) { // works because first compnent is never a opertor
assert(!struct.isOperator());
posX += cw + lineMin;
}
double x = posX;
double y = posY;
comp.setComponentBounds((int) x, (int) y, (int) cw, (int) ch);
//System.out.println("Layout [x, ,y, w, h]: " + (int) x + ", " + (int) y + ", " + (int) cw + ", " + (int) ch);
}
}
Rectangle rect = this.getBounds();
rect.setSize((int) posX, (int) rect.getHeight());
this.setBounds(rect);
}
private List<IComponentStruct> getIComponents() {
List<IComponentStruct> returnValue = new ArrayList<IComponentStruct>();
Component[] comps = this.getComponents();
//comps = CollectionTools.revertArray(comps);
for (int counter = 0; counter < comps.length; counter++) {
boolean isOperator = (ILine.class.isInstance(comps[counter]));
IComponent comp = (IComponent) comps[counter];
returnValue.add(new IComponentStruct(comp, isOperator));
}
return returnValue;
}
/**
* if true, the panel is used to draw Multimedia objects and operator
* this means, when deleting objects, the previous operator (ILine) is removed too
*
* @return true if the panel is used to draw Multimedia objects and operator, false otherwise
*/
public boolean isMathMode() {
return isMathMode;
}
/**
* if true, the panel is used to draw Mulmiedia objects and operator
* this means, when deleting objects, the previous operator (ILine) is removed too
*/
public void setMathMode(boolean mathMode) {
isMathMode = mathMode;
}
/*public void paint(Graphics g) {
super.paint(g);
}*/
}
class IComponentStruct {
private IComponent component;
private boolean isOperator;
public IComponentStruct(IComponent component, boolean isOperator) {
setComponent(component);
setOperator(isOperator);
}
public boolean equals(IComponent a_component) {
boolean returnValue;
returnValue = (a_component == component);
return returnValue;
}
public IComponent getComponent() {
return component;
}
public void setComponent(IComponent component) {
this.component = component;
}
public boolean isOperator() {
return isOperator;
}
public void setOperator(boolean operator) {
isOperator = operator;
}
}