// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea
// Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com
// Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
// Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/
package graphtea.ui.extension;
import graphtea.graph.graph.GraphModel;
import graphtea.platform.core.AEvent;
import graphtea.platform.core.AbstractAction;
import graphtea.platform.core.BlackBoard;
import graphtea.platform.extension.Extension;
import graphtea.platform.lang.CommandAttitude;
import graphtea.platform.parameter.Parameter;
import graphtea.platform.parameter.Parametrizable;
import graphtea.plugins.graphgenerator.core.extension.GraphGeneratorExtension;
import graphtea.plugins.main.extension.GraphActionExtension;
import graphtea.plugins.reports.extension.GraphReportExtension;
import graphtea.ui.ParameterShower;
import graphtea.ui.UIUtils;
import graphtea.ui.components.ExtensionConfigFrame;
import graphtea.ui.components.GFrame;
import graphtea.ui.components.gmenu.GMenuBar;
import graphtea.ui.components.gmenu.GMenuItem;
import graphtea.ui.xml.UIHandlerImpl;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
/**
* the base class for creating extension handlers
* the implementing class will have a menu assigned to it automatically the name of the menu will be
* from the constructors parametr(sp) and the will also listen to UI.getUIEvent(sp.getName())
*
* @author azin azadi
*/
public abstract class AbstractExtensionAction<t extends Extension> extends AbstractAction implements ActionListener {
//todo: Write how to create new extension types document.
protected JMenu parentMenu;
public GMenuItem menuItem;
ExtensionConfigFrame ecf;
/**
* a button which will be added to the right of menu item
*/
protected JButton extraButton;
public final String actionId;
public t getTarget() {
return target;
}
public t target;
static HashMap<String, JMenu> reportSubMenus = new HashMap<>();
static HashMap<String, JMenu> reportSubSubMenus = new HashMap<>();
static HashMap<String, JMenu> generateSubMenus = new HashMap<>();
static HashMap<String, JMenu> operatorsSubmenus = new HashMap<>();
public AbstractExtensionAction(BlackBoard bb, t sp) {
super(bb);
target = sp;
String name = getMenuNamePrefix() + sp.getName();
actionId = name + sp.getDescription() + target.getClass().getName();
listen4Event(UIUtils.getUIEventKey(actionId));
if (!name.equals("")) {
menuItem = createMenuItem(name, actionId, bb);
parentMenu = getParentMenu();
if (parentMenu.getText().equalsIgnoreCase("reports")) {
GraphReportExtension<t> temp = (GraphReportExtension<t>) sp;
if (temp.getCategory() != null) {
if(!temp.getCategory().contains("-")) {
JMenu categoryMenu;
if (!reportSubMenus.containsKey(temp.getCategory())) {
categoryMenu = new JMenu(temp.getCategory());
reportSubMenus.put(temp.getCategory(), categoryMenu);
} else
categoryMenu = reportSubMenus.get(temp.getCategory());
GMenuBar.insert(parentMenu, categoryMenu, getMenuPlace());
GMenuBar.insert(categoryMenu, menuItem, getMenuPlace());
} else {
JMenu categoryMenu;
JMenu subsub;
String cat = temp.getCategory();
String sub = cat.substring(0, cat.indexOf("-"));
String subsubStr = cat.substring(cat.indexOf("-")+1);
if (!reportSubMenus.containsKey(sub)) {
categoryMenu = new JMenu(sub);
reportSubMenus.put(sub, categoryMenu);
} else
categoryMenu = reportSubMenus.get(sub);
if(!reportSubSubMenus.containsKey(subsubStr)) {
subsub = new JMenu(subsubStr);
reportSubSubMenus.put(subsubStr,subsub);
} else {
subsub=reportSubSubMenus.get(subsubStr);
}
GMenuBar.insert(parentMenu, categoryMenu, getMenuPlace());
GMenuBar.insert(categoryMenu, subsub, getMenuPlace());
GMenuBar.insert(subsub, menuItem, getMenuPlace());
}
} else
GMenuBar.insert(parentMenu, menuItem, getMenuPlace());
} else if (parentMenu.getText().equalsIgnoreCase("generate graph")) {
GraphGeneratorExtension temp = (GraphGeneratorExtension) sp;
if (temp.getCategory() != null) {
JMenu categoryMenu;
if (!generateSubMenus.containsKey(temp.getCategory())) {
categoryMenu = new JMenu(temp.getCategory());
generateSubMenus.put(temp.getCategory(), categoryMenu);
} else
categoryMenu = generateSubMenus.get(temp.getCategory());
GMenuBar.insert(parentMenu, categoryMenu, getMenuPlace());
GMenuBar.insert(categoryMenu, menuItem, getMenuPlace());
} else
GMenuBar.insert(parentMenu, menuItem, getMenuPlace());
} else if (parentMenu.getText().equalsIgnoreCase("operators")) {
GraphActionExtension temp = (GraphActionExtension) sp;
if (temp.getCategory() != null) {
JMenu categoryMenu;
if (!operatorsSubmenus.containsKey(temp.getCategory())) {
categoryMenu = new JMenu(temp.getCategory());
operatorsSubmenus.put(temp.getCategory(), categoryMenu);
} else
categoryMenu = operatorsSubmenus.get(temp.getCategory());
GMenuBar.insert(parentMenu, categoryMenu, getMenuPlace());
GMenuBar.insert(categoryMenu, menuItem, getMenuPlace());
} else
GMenuBar.insert(parentMenu, menuItem, getMenuPlace());
} else if (parentMenu != null)
GMenuBar.insert(parentMenu, menuItem, getMenuPlace());
}
createExtensionCommandsForCommandLine();
}
/**
* It is a XML-Based UI concept
*
* @return the place which the extension menu will be inserted in its parents menu, the place is
* only a comparative value, it means that Menu Items with bigger place will be inserted after smaller place Menue Items
*/
protected int getMenuPlace() {
return target.getName().charAt(0) * 1000 + target.getName().charAt(1);
}
/**
* if you want to create custom menues for your extension (i.e. want to add some extra components to it) you should
* override this method.
*
* @param name The name of the menu
* @param actionId The action id
* @param bb The blackboard
* @return The menu item
* @see graphtea.plugins.algorithmanimator.extension.AlgorithmExtensionAction
*/
protected final GMenuItem createMenuItem(String name, String actionId, BlackBoard bb) {
int index = Math.max(name.indexOf(UIHandlerImpl.menueIndexChar), 0);
String labelString = name.replace(UIHandlerImpl.menueIndexChar + "", "");
if (isInsertExtraButtonToMenuItem()) {
GMenuItem menuItem = new GMenuItem(labelString, actionId, bb, null, index) {
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
Dimension bps = extraButton.getPreferredSize();
preferredSize.width += bps.getWidth() + 4;
preferredSize.height = (int) Math.max(preferredSize.height, bps.getHeight()) + 1;
return preferredSize;
}
};
String imageURL = "/graphtea/plugins/main/resources/edit16_.gif";
extraButton = new JButton(new ImageIcon(getClass().getResource(imageURL)));
extraButton.setBorder(new EmptyBorder(0, 0, 0, 0));
extraButton.addActionListener(this);
extraButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
actionPerformed(null);
}
});
menuItem.setLayout(new BorderLayout());
menuItem.add(extraButton, BorderLayout.EAST);
return menuItem;
} else
return new GMenuItem(name, actionId, bb);
}
/**
* determines wheter to insert an extra button at the right side of mene item,
* normally this is true whenever the target extension implements Parametrizable (have some parameters)
* on this mode on pressing the button a dialog for setting the parameters will be shown, and then
* it will be executed, if the user clicks the menu item directly the extension will be
* performed without asking of parameters.
* <p/>
* if you want to override this method for your own ExtensionAction
* NOTE that on pressing the button the actionPerformed will be called, so you can
* do what you want to do by overriding that method.
*
* @return true to insert the extra button, false to no insert it.
* @see Parametrizable
* @see Parameter
* @see graphtea.plugins.algorithmanimator.extension.AlgorithmExtensionAction
*/
protected boolean isInsertExtraButtonToMenuItem() {
return false; //target instanceof Parametrizable; we dont want this button for now. just go with the simple interface
}
/**
* inorder if you created a new type of extension and for that extension you want to do some thing different
* when it is called on commandline (i.e. in normal state it uses some GUI functionalities and you want to avoid them)
* you can override this method and do what you want, which will
* be called whenever your extension called from commandline
* for an example see GraphGeneratorExtensionAction
*
* @see graphtea.plugins.graphgenerator.core.extension.GraphGeneratorExtensionAction
*/
public Object performExtensionInCommandLine() {
performExtension();
return null;
}
protected void createExtensionCommandsForCommandLine() {
final AbstractExtensionAction<t> ths = this;
final t trgClass = target;
final CommandAttitude comati = trgClass.getClass().getAnnotation(CommandAttitude.class);
String command = "";
String cname;
String abrv;
String desc;
if (comati != null) {
// Shell.set_variable("_" + target.getClass().getSimpleName(), target);
cname = comati.name();
abrv = comati.abbreviation();
desc = comati.description();
if (desc == null || desc.equals(""))
desc = target.getDescription();
} else {
cname = target.getClass().getSimpleName();
abrv = "";
desc = target.getDescription();
}
command += cname + "(";
String help = "";
for (Field f : target.getClass().getFields()) {
if (f.getAnnotation(Parameter.class) != null) {
command += f.getType().getName()
+ " "
+ f.getName() + ",";
help += "_" + target.getClass().getSimpleName()
+ "."
+ f.getName()
+ " = "
+ f.getName()
+ ";\n";
}
}
if (command.endsWith(","))
command = command.substring(0, command.length() - 1);
command += ")\n{";
// System.out.println(command);
ExtensionShellCommandProvider.addCommand(ths, trgClass, cname, abrv, command, desc, help);
}
/**
* to put a prefix before the name of your extension menu override this method
*/
protected String getMenuNamePrefix() {
return "";
}
/**
* gets a menu for adding the sub menu, if returns null, no submenu will added!
*/
protected JMenu getParentMenu() {
GFrame f = UIUtils.getGFrame(blackboard);
String mname = getParentMenuName();
return f.getMenu().getUniqueMenu(mname, -1);
}
/**
* first checks if o instanceof Parametrizable if so, shows an
* editor for it's Parameters.
*
* @param o The object
* @return true if o isn't an instance of Parametrizable or the user cancells the editing
*/
public boolean testAndSetParameters(Object o) {
if (o instanceof Parametrizable) {
ParameterShower ps = new ParameterShower();
return ps.show((Parametrizable) o);
} else
return true;
}
/**
* removes all UI Components that are created for the extension (menues, ...)
*/
public void removeCreatedUIComponents() {
if (parentMenu != null && menuItem != null) {
parentMenu.remove(menuItem);
//if parent menu is empty remove it and so on.
if (parentMenu.getMenuComponentCount() == 0) {
parentMenu.getParent().remove(parentMenu);
}
}
}
/**
* returns the menu name that the menuitem of this action is its child
*/
public abstract String getParentMenuName();
public final void performAction(String eventKey, Object value) {
if (testAndSetParameters(target))
performExtension();
}
public void track(){
blackboard.setData("ATrack", new AEvent().category(getParentMenuName()).action(target.getName()));
}
/**
* occurs whenever extraButton pressed
* <p/>
* =
*/
public void actionPerformed(ActionEvent e) {
parentMenu.setSelected(false);
if (testAndSetParameters(target))
performExtension();
}
public abstract void performExtension();
public GraphModel generateGraph(){return new GraphModel();}
}