package com.baselet.diagram.io;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import com.baselet.control.basics.geom.Rectangle;
import com.baselet.control.enums.ElementId;
import com.baselet.diagram.DiagramHandler;
import com.baselet.diagram.DrawPanel;
import com.baselet.element.ElementFactorySwing;
import com.baselet.element.NewGridElement;
import com.baselet.element.facet.common.GroupFacet;
import com.baselet.element.interfaces.GridElement;
import com.baselet.element.old.custom.CustomElementCompiler;
import com.baselet.element.old.element.ErrorOccurred;
import com.baselet.gui.BaseGUI;
import com.baselet.gui.CurrentGui;
import com.baselet.gui.command.HelpPanelChanged;
/**
* Describes what should happen with parsed elements from the input file
* eg: set DiagramHandler variables, create GridElements etc.
*/
public class InputHandler extends DefaultHandler {
private static final String[] oldGridElementPackages = new String[] { "com.baselet.element.old.element", "com.baselet.element.old.allinone", "com.baselet.element.old.custom" };
private static final Logger log = LoggerFactory.getLogger(InputHandler.class);
private DrawPanel _p = null;
private GridElement e = null;
private String elementtext;
private int x;
private int y;
private int w;
private int h;
private String entityname;
private String code;
private String panel_attributes;
private String additional_attributes;
private Integer currentGroup;
private final DiagramHandler handler;
// to be backward compatible - add list of old elements that were removed so that they are ignored when loading old files
private final List<String> ignoreElements;
private String id; // Experimental elements have an id instead of an entityname
public InputHandler(DiagramHandler handler) {
this.handler = handler;
_p = handler.getDrawPanel();
ignoreElements = new ArrayList<String>();
ignoreElements.add("main.control.Group");
currentGroup = null;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
elementtext = "";
if (qName.equals("element")) {
panel_attributes = "";
additional_attributes = "";
code = null;
}
if (qName.equals("group")) { // TODO remove group-handling in InputHandler. Until UMLet v13, groups used own element-tags in XML. This has changed to the property group=x, so this handling is only for backwards compatibility
currentGroup = handler.getDrawPanel().getSelector().getUnusedGroup();
}
}
@Override
public void endElement(String uri, String localName, String qName) {
String elementname = qName; // [UB]: we are not name-space aware, so use the qualified name
if (elementname.equals("help_text")) {
handler.setHelpText(elementtext);
handler.getFontHandler().setDiagramDefaultFontSize(HelpPanelChanged.getFontsize(elementtext));
handler.getFontHandler().setDiagramDefaultFontFamily(HelpPanelChanged.getFontfamily(elementtext));
BaseGUI gui = CurrentGui.getInstance().getGui();
if (gui != null && gui.getPropertyPane() != null) { // issue 244: in batchmode, a file can have a help_text but gui will be null
gui.getPropertyPane().switchToNonElement(elementtext);
}
}
else if (elementname.equals("zoom_level")) {
if (handler != null) {
handler.setGridSize(Integer.parseInt(elementtext));
}
}
else if (elementname.equals("group")) {
currentGroup = null;
}
else if (elementname.equals("element")) {
if (id != null) {
try {
NewGridElement e = ElementFactorySwing.create(ElementId.valueOf(id), new Rectangle(x, y, w, h), panel_attributes, additional_attributes, handler);
if (currentGroup != null) {
e.setProperty(GroupFacet.KEY, currentGroup);
}
_p.addElement(e);
} catch (Exception e) {
log.error("Cannot instantiate element with id: " + id, e);
}
id = null;
}
else if (!ignoreElements.contains(entityname)) { // OldGridElement handling which can be removed as soon as all OldGridElements have been replaced
try {
if (code == null) {
e = InputHandler.getOldGridElementFromPath(entityname);
}
else {
e = CustomElementCompiler.getInstance().genEntity(code);
}
} catch (InstantiationException e1) {
e = new ErrorOccurred();
} catch (IllegalAccessException e1) {
e = new ErrorOccurred();
} catch (ClassNotFoundException e1) {
e = new ErrorOccurred();
}
e.setRectangle(new Rectangle(x, y, w, h));
e.setPanelAttributes(panel_attributes);
e.setAdditionalAttributes(additional_attributes);
handler.setHandlerAndInitListeners(e);
if (currentGroup != null) {
e.setProperty(GroupFacet.KEY, currentGroup);
}
_p.addElement(e);
}
}
else if (elementname.equals("type")) {
entityname = elementtext;
}
else if (elementname.equals("id")) { // new elements have an id
id = elementtext;
}
else if (elementname.equals("x")) {
Integer i = Integer.valueOf(elementtext);
x = i.intValue();
}
else if (elementname.equals("y")) {
Integer i = Integer.valueOf(elementtext);
y = i.intValue();
}
else if (elementname.equals("w")) {
Integer i = Integer.valueOf(elementtext);
w = i.intValue();
}
else if (elementname.equals("h")) {
Integer i = Integer.valueOf(elementtext);
h = i.intValue();
}
else if (elementname.equals("panel_attributes")) {
panel_attributes = elementtext;
}
else if (elementname.equals("additional_attributes")) {
additional_attributes = elementtext;
}
else if (elementname.equals("custom_code")) {
code = elementtext;
}
}
@Override
public void characters(char[] ch, int start, int length) {
elementtext += new String(ch).substring(start, start + length);
}
private static GridElement getOldGridElementFromPath(String path) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Class<?> foundClass = null;
String className = path.substring(path.lastIndexOf("."));
for (String possPackage : oldGridElementPackages) {
try {
foundClass = Thread.currentThread().getContextClassLoader().loadClass(possPackage + className);
break;
} catch (ClassNotFoundException e1) {/* do nothing; try next package */}
}
if (foundClass == null) {
ClassNotFoundException ex = new ClassNotFoundException("class " + path + " not found");
log.error(null, ex);
throw ex;
}
else {
return (GridElement) foundClass.newInstance();
}
}
}