AS3 - Tabbed design for traits

This commit is contained in:
Jindra Pet��k
2011-07-11 12:20:21 +02:00
parent fdbd5b2ef8
commit a749e1f997
10 changed files with 324 additions and 151 deletions
@@ -71,8 +71,7 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane {
JOptionPane.showMessageDialog(this, (ex.text + " on line " + ex.line)); JOptionPane.showMessageDialog(this, (ex.text + " on line " + ex.line));
selectLine((int) ex.line); selectLine((int) ex.line);
return false; return false;
} }
JOptionPane.showMessageDialog(this, ("Code Saved"));
return true; return true;
} }
@@ -59,7 +59,7 @@ public class ClassesListTree extends JTree implements TreeSelectionListener {
public void run() { public void run() {
Main.abcMainFrame.navigator.setClassIndex(tp.classIndex); Main.abcMainFrame.navigator.setClassIndex(tp.classIndex);
Main.abcMainFrame.decompiledTextArea.setClassIndex(tp.classIndex, abc); Main.abcMainFrame.decompiledTextArea.setClassIndex(tp.classIndex, abc);
Main.abcMainFrame.sourceTextArea.setText(""); Main.abcMainFrame.detailPanel.methodTraitPanel.methodCodePanel.sourceTextArea.setText("");
Main.stopWork(); Main.stopWork();
} }
}).start(); }).start();
@@ -40,13 +40,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements MouseL
public void setNoTrait() public void setNoTrait()
{ {
Main.abcMainFrame.sourceTextArea.setText(""); Main.abcMainFrame.detailPanel.showCard(DetailPanel.UNSUPPORTED_TRAIT_CARD);
Main.abcMainFrame.methodBodyPanel.loadFromBody(null);
Main.abcMainFrame.methodBodyLabel.setText("Uneditable trait");
Main.abcMainFrame.methodBodyPanel.setVisible(false);
Main.abcMainFrame.sourceTextArea.setVisible(false);
Main.abcMainFrame.buttonsPanel.setVisible(false);
Main.abcMainFrame.sourceTextArea.bodyIndex=-1;
} }
public void caretUpdate(CaretEvent e) { public void caretUpdate(CaretEvent e) {
@@ -60,24 +54,16 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements MouseL
setNoTrait(); setNoTrait();
break; break;
} }
Main.abcMainFrame.methodBodyPanel.setVisible(true); Main.abcMainFrame.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD);
Main.abcMainFrame.sourceTextArea.setVisible(true);
Main.abcMainFrame.buttonsPanel.setVisible(true);
lastTraitIndex = (int) th.offset; lastTraitIndex = (int) th.offset;
if (Main.abcMainFrame.sourceTextArea.bodyIndex != bi) { if (Main.abcMainFrame.detailPanel.methodTraitPanel.methodCodePanel.sourceTextArea.bodyIndex != bi) {
/*try { Main.abcMainFrame.detailPanel.methodTraitPanel.methodCodePanel.sourceTextArea.setBodyIndex(bi, abc);
abc.bodies[bi].code.clearCode(abc.constants, abc.bodies[bi]); Main.abcMainFrame.detailPanel.methodTraitPanel.methodBodyParamsPanel.loadFromBody(abc.bodies[bi]);
} catch (ConvertException ex) {
Logger.getLogger(DecompiledEditorPane.class.getName()).log(Level.SEVERE, null, ex);
}*/
Main.abcMainFrame.sourceTextArea.setBodyIndex(bi, abc);
Main.abcMainFrame.methodBodyPanel.loadFromBody(abc.bodies[bi]);
Main.abcMainFrame.methodBodyLabel.setText("Method body #"+bi);
} }
for (Highlighting h : highlights) { for (Highlighting h : highlights) {
if ((pos >= h.startPos) && (pos < h.startPos + h.len)) { if ((pos >= h.startPos) && (pos < h.startPos + h.len)) {
try { try {
Main.abcMainFrame.sourceTextArea.selectInstruction(abc.bodies[bi].code.adr2pos(h.offset)); Main.abcMainFrame.detailPanel.methodTraitPanel.methodCodePanel.sourceTextArea.selectInstruction(abc.bodies[bi].code.adr2pos(h.offset));
} catch (ConvertException ex) { } catch (ConvertException ex) {
} }
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2011 JPEXS
*
* 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 com.jpexs.asdec.abc.gui;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
/**
*
* @author JPEXS
*/
public class DetailPanel extends JPanel implements ActionListener {
public MethodTraitDetailPanel methodTraitPanel;
public JPanel unsupportedTraitPanel;
public static final String METHOD_TRAIT_CARD="MethodTrait";
public static final String UNSUPPORTED_TRAIT_CARD="UnsupportedTrait";
private JPanel innerPanel;
public JButton saveButton;
private HashMap<String,JComponent> cardMap=new HashMap<String,JComponent>();
private String selectedCard;
public DetailPanel()
{
innerPanel=new JPanel();
CardLayout layout=new CardLayout();
innerPanel.setLayout(layout);
methodTraitPanel=new MethodTraitDetailPanel();
cardMap.put(METHOD_TRAIT_CARD, methodTraitPanel);
unsupportedTraitPanel=new JPanel(new BorderLayout());
JLabel unsup=new JLabel("Editing of this trait type is currently unsupported",SwingConstants.CENTER);
unsupportedTraitPanel.add(unsup,BorderLayout.CENTER);
cardMap.put(UNSUPPORTED_TRAIT_CARD, unsupportedTraitPanel);
for(String key:cardMap.keySet())
{
innerPanel.add(cardMap.get(key),key);
}
setLayout(new BorderLayout());
add(innerPanel,BorderLayout.CENTER);
JPanel buttonsPanel=new JPanel();
buttonsPanel.setLayout(new FlowLayout());
saveButton = new JButton("Save");
saveButton.setActionCommand("SAVEDETAIL");
saveButton.addActionListener(this);
buttonsPanel.add(saveButton);
add(buttonsPanel,BorderLayout.SOUTH);
selectedCard=UNSUPPORTED_TRAIT_CARD;
layout.show(innerPanel, UNSUPPORTED_TRAIT_CARD);
saveButton.setVisible(false);
}
public void showCard(String name)
{
CardLayout layout=(CardLayout)innerPanel.getLayout();
layout.show(innerPanel, name);
saveButton.setVisible(cardMap.get(name) instanceof TraitDetail);
selectedCard=name;
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("SAVEDETAIL")) {
if(cardMap.get(selectedCard) instanceof TraitDetail)
{
if(((TraitDetail)cardMap.get(selectedCard)).save())
{
JOptionPane.showMessageDialog(this, "Trait Successfully saved");
}
}
}
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011 Jindra * Copyright (C) 2011 JPEXS
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -40,7 +40,7 @@ import jsyntaxpane.syntaxkits.Flasm3SyntaxKit;
public class MainFrame extends JFrame implements ActionListener, ItemListener { public class MainFrame extends JFrame implements ActionListener, ItemListener {
public ASMSourceEditorPane sourceTextArea;
public TraitsList navigator; public TraitsList navigator;
public ClassesListTree classTree; public ClassesListTree classTree;
public ABC abc; public ABC abc;
@@ -60,11 +60,9 @@ public class MainFrame extends JFrame implements ActionListener, ItemListener {
public LoadingPanel loadingPanel = new LoadingPanel(20, 20); public LoadingPanel loadingPanel = new LoadingPanel(20, 20);
public JLabel statusLabel = new JLabel(""); public JLabel statusLabel = new JLabel("");
public JLabel asmLabel = new JLabel("P-code source (editable)"); public JLabel asmLabel = new JLabel("P-code source (editable)");
public JLabel decLabel = new JLabel("ActionScript source"); public JLabel decLabel = new JLabel("ActionScript source");
public MethodBodyPanel methodBodyPanel; public DetailPanel detailPanel;
public JLabel methodBodyLabel;
public JPanel detailPanel;
public JPanel buttonsPanel;
public void setStatus(String s) { public void setStatus(String s) {
if (s.equals("")) { if (s.equals("")) {
@@ -173,60 +171,18 @@ public class MainFrame extends JFrame implements ActionListener, ItemListener {
setSize(1024, 600); setSize(1024, 600);
this.abc = list.get(listIndex).abc; this.abc = list.get(listIndex).abc;
getContentPane().setLayout(new BorderLayout()); getContentPane().setLayout(new BorderLayout());
sourceTextArea = new ASMSourceEditorPane();
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new BorderLayout());
rightPanel.add(new JScrollPane(sourceTextArea), BorderLayout.CENTER);
sourceTextArea.setContentType("text/flasm3");
buttonsPanel = new JPanel();
buttonsPanel.setLayout(new FlowLayout());
JButton verifyButton = new JButton("Verify");
verifyButton.setActionCommand("VERIFYBODY");
verifyButton.addActionListener(this);
JButton saveButton = new JButton("Save");
saveButton.setActionCommand("SAVEBODY");
saveButton.addActionListener(this);
JButton graphButton = new JButton("Graph");
graphButton.setActionCommand("GRAPH");
graphButton.addActionListener(this);
JButton execButton = new JButton("Execute");
execButton.setActionCommand("EXEC");
execButton.addActionListener(this);
//buttonsPan.add(graphButton);
buttonsPanel.add(saveButton);
// buttonsPan.add(execButton);
rightPanel.add(buttonsPanel, BorderLayout.SOUTH);
decompiledTextArea = new DecompiledEditorPane(); decompiledTextArea = new DecompiledEditorPane();
decompiledScrollPane = new JScrollPane(decompiledTextArea); decompiledScrollPane = new JScrollPane(decompiledTextArea);
detailPanel=new JPanel(); detailPanel=new DetailPanel();
detailPanel.setLayout(new BorderLayout());
methodBodyPanel=new MethodBodyPanel();
JPanel methodBodyPanel1=new JPanel();
methodBodyPanel1.setLayout(new BorderLayout());
methodBodyPanel1.add(methodBodyPanel,BorderLayout.CENTER);
methodBodyLabel=new JLabel("Method body");
methodBodyLabel.setHorizontalAlignment(SwingConstants.CENTER);
methodBodyLabel.setBorder(new BevelBorder(BevelBorder.RAISED));
methodBodyPanel1.add(methodBodyLabel,BorderLayout.NORTH);
detailPanel.add(methodBodyPanel1,BorderLayout.NORTH);
JPanel pcodePanel = new JPanel();
pcodePanel.setLayout(new BorderLayout());
pcodePanel.add(rightPanel, BorderLayout.CENTER);
//pcodePanel.add(asmLabel, BorderLayout.NORTH);
detailPanel.add(pcodePanel,BorderLayout.CENTER);
//asmLabel.setHorizontalAlignment(SwingConstants.CENTER);
//asmLabel.setBorder(new BevelBorder(BevelBorder.RAISED));
JPanel panB = new JPanel(); JPanel panB = new JPanel();
panB.setLayout(new BorderLayout()); panB.setLayout(new BorderLayout());
panB.add(decompiledScrollPane, BorderLayout.CENTER); panB.add(decompiledScrollPane, BorderLayout.CENTER);
@@ -368,29 +324,11 @@ public class MainFrame extends JFrame implements ActionListener, ItemListener {
Main.exit(); Main.exit();
} }
if (Main.isWorking()) return; if (Main.isWorking()) return;
if (e.getActionCommand().equals("GRAPH")) {
sourceTextArea.graph();
}
if (e.getActionCommand().equals("EXEC")) {
sourceTextArea.exec();
}
if (e.getActionCommand().equals("SHOWPROXY")) { if (e.getActionCommand().equals("SHOWPROXY")) {
Main.showProxy(); Main.showProxy();
} }
if (e.getActionCommand().equals("VERIFYBODY")) {
sourceTextArea.verify(abc.constants, abc);
}
if (e.getActionCommand().equals("SAVEBODY")) {
if(sourceTextArea.save(abc.constants))
{
methodBodyPanel.save();
int lasttrait=decompiledTextArea.lastTraitIndex;
Main.abcMainFrame.decompiledTextArea.reloadClass();
Main.abcMainFrame.decompiledTextArea.gotoTrait(lasttrait);
}
}
if (e.getActionCommand().equals("SAVE")) { if (e.getActionCommand().equals("SAVE")) {
try { try {
Main.saveFile(Main.file); Main.saveFile(Main.file);
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011 Jindra * Copyright (C) 2011 JPEXS
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -25,81 +25,71 @@ import java.text.NumberFormat;
import javax.swing.JFormattedTextField; import javax.swing.JFormattedTextField;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SpringLayout; import javax.swing.SwingConstants;
/** /**
* *
* @author Jindra * @author JPEXS
*/ */
public class MethodBodyPanel extends JPanel { public class MethodBodyParamsPanel extends JPanel {
public JLabel maxStackLabel = new JLabel("Max stack:"); public JLabel maxStackLabel = new JLabel("Max stack:",SwingConstants.RIGHT);
public JFormattedTextField maxStackField = new JFormattedTextField(NumberFormat.getNumberInstance()); public JFormattedTextField maxStackField = new JFormattedTextField(NumberFormat.getNumberInstance());
public JLabel localCountLabel = new JLabel("Local registers count:"); public JLabel localCountLabel = new JLabel("Local registers count:",SwingConstants.RIGHT);
public JFormattedTextField localCountField = new JFormattedTextField(NumberFormat.getNumberInstance()); public JFormattedTextField localCountField = new JFormattedTextField(NumberFormat.getNumberInstance());
public JLabel initScopeDepthLabel = new JLabel("Minimum scope depth:"); public JLabel initScopeDepthLabel = new JLabel("Minimum scope depth:",SwingConstants.RIGHT);
public JFormattedTextField initScopeDepthField = new JFormattedTextField(NumberFormat.getNumberInstance()); public JFormattedTextField initScopeDepthField = new JFormattedTextField(NumberFormat.getNumberInstance());
public JLabel maxScopeDepthLabel = new JLabel("Maximum scope depth:"); public JLabel maxScopeDepthLabel = new JLabel("Maximum scope depth:",SwingConstants.RIGHT);
public JFormattedTextField maxScopeDepthField = new JFormattedTextField(NumberFormat.getNumberInstance()); public JFormattedTextField maxScopeDepthField = new JFormattedTextField(NumberFormat.getNumberInstance());
public MethodBody body; public MethodBody body;
public MethodBodyPanel() { public MethodBodyParamsPanel() {
setLayout(new GridLayout(4,1)); setLayout(null);
maxStackField.setPreferredSize(new Dimension(75, 20));
JPanel pan1=new JPanel();
pan1.setLayout(new FlowLayout());
pan1.add(maxStackLabel);
pan1.add(maxStackField);
add(pan1);
localCountField.setPreferredSize(new Dimension(75, 20));
JPanel pan2=new JPanel();
pan2.setLayout(new FlowLayout());
pan2.add(localCountLabel);
pan2.add(localCountField);
add(pan2); maxStackLabel.setBounds(10, 10, 150, 25);
initScopeDepthField.setPreferredSize(new Dimension(75, 20)); maxStackField.setBounds(10+150+10, 10, 75, 25);
JPanel pan3=new JPanel(); add(maxStackLabel);
pan3.setLayout(new FlowLayout()); add(maxStackField);
pan3.add(initScopeDepthLabel);
pan3.add(initScopeDepthField);
add(pan3); localCountLabel.setBounds(10, 10+30, 150, 25);
maxScopeDepthField.setPreferredSize(new Dimension(75, 20)); localCountField.setBounds(10+150+10, 10+30, 75, 25);
JPanel pan4=new JPanel(); add(localCountLabel);
pan4.setLayout(new FlowLayout()); add(localCountField);
pan4.add(maxScopeDepthLabel);
pan4.add(maxScopeDepthField); initScopeDepthLabel.setBounds(10, 10+30+30, 150, 25);
add(pan4); initScopeDepthField.setBounds(10+150+10, 10+30+30, 75, 25);
setPreferredSize(new Dimension(150,150)); add(initScopeDepthLabel);
add(initScopeDepthField);
maxScopeDepthLabel.setBounds(10, 10+30+30+30, 150, 25);
maxScopeDepthField.setBounds(10+150+10, 10+30+30+30, 75, 25);
add(maxScopeDepthLabel);
add(maxScopeDepthField);
setPreferredSize(new Dimension(300,150));
} }
public void loadFromBody(MethodBody body) public void loadFromBody(MethodBody body) {
{ this.body = body;
this.body=body; if (body == null) {
if(body==null){
maxStackField.setText("0"); maxStackField.setText("0");
localCountField.setText("0"); localCountField.setText("0");
initScopeDepthField.setText("0"); initScopeDepthField.setText("0");
maxScopeDepthField.setText("0"); maxScopeDepthField.setText("0");
return; return;
} }
maxStackField.setText(""+body.max_stack); maxStackField.setText("" + body.max_stack);
localCountField.setText(""+body.max_regs); localCountField.setText("" + body.max_regs);
initScopeDepthField.setText(""+body.init_scope_depth); initScopeDepthField.setText("" + body.init_scope_depth);
maxScopeDepthField.setText(""+body.max_scope_depth); maxScopeDepthField.setText("" + body.max_scope_depth);
} }
public void save(){ public void save() {
if(body!=null) if (body != null) {
{ body.max_stack = Integer.parseInt(maxStackField.getText());
body.max_stack=Integer.parseInt(maxStackField.getText()); body.max_regs = Integer.parseInt(localCountField.getText());
body.max_regs=Integer.parseInt(localCountField.getText()); body.init_scope_depth = Integer.parseInt(initScopeDepthField.getText());
body.init_scope_depth=Integer.parseInt(initScopeDepthField.getText()); body.max_scope_depth = Integer.parseInt(maxScopeDepthField.getText());
body.max_scope_depth=Integer.parseInt(maxScopeDepthField.getText());
} }
} }
} }
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2011 JPEXS
*
* 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 com.jpexs.asdec.abc.gui;
import com.jpexs.asdec.Main;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
*
* @author JPEXS
*/
public class MethodCodePanel extends JPanel implements ActionListener {
public ASMSourceEditorPane sourceTextArea;
public JPanel buttonsPanel;
public MethodCodePanel() {
sourceTextArea = new ASMSourceEditorPane();
setLayout(new BorderLayout());
add(new JScrollPane(sourceTextArea), BorderLayout.CENTER);
sourceTextArea.setContentType("text/flasm3");
buttonsPanel = new JPanel();
buttonsPanel.setLayout(new FlowLayout());
JButton verifyButton = new JButton("Verify");
verifyButton.setActionCommand("VERIFYBODY");
verifyButton.addActionListener(this);
JButton graphButton = new JButton("Graph");
graphButton.setActionCommand("GRAPH");
graphButton.addActionListener(this);
JButton execButton = new JButton("Execute");
execButton.setActionCommand("EXEC");
execButton.addActionListener(this);
//buttonsPan.add(graphButton);
// buttonsPanel.add(saveButton);
// buttonsPan.add(execButton);
//add(buttonsPanel, BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e) {
if (Main.isWorking()) return;
if (e.getActionCommand().equals("GRAPH")) {
sourceTextArea.graph();
}
if (e.getActionCommand().equals("EXEC")) {
sourceTextArea.exec();
}
if (e.getActionCommand().equals("VERIFYBODY")) {
sourceTextArea.verify(Main.abcMainFrame.abc.constants, Main.abcMainFrame.abc);
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2011 JPEXS
*
* 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 com.jpexs.asdec.abc.gui;
import com.jpexs.asdec.Main;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
/**
*
* @author JPEXS
*/
public class MethodTraitDetailPanel extends JTabbedPane implements TraitDetail {
public MethodCodePanel methodCodePanel;
public MethodBodyParamsPanel methodBodyParamsPanel;
public MethodTraitDetailPanel() {
methodCodePanel = new MethodCodePanel();
methodBodyParamsPanel = new MethodBodyParamsPanel();
addTab("MethodBody Code", methodCodePanel);
addTab("MethodBody params", new JScrollPane(methodBodyParamsPanel));
}
public boolean save() {
if (methodCodePanel.sourceTextArea.save(Main.abcMainFrame.abc.constants)) {
methodBodyParamsPanel.save();
int lasttrait = Main.abcMainFrame.decompiledTextArea.lastTraitIndex;
Main.abcMainFrame.decompiledTextArea.reloadClass();
Main.abcMainFrame.decompiledTextArea.gotoTrait(lasttrait);
return true;
}
return false;
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2011 JPEXS
*
* 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 com.jpexs.asdec.abc.gui;
/**
*
* @author JPEXS
*/
public interface TraitDetail {
public boolean save();
}