/* * Copyright (c) 2010-2016, Sikuli.org, sikulix.com * Released under the MIT License. * */ package org.sikuli.ide; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import org.sikuli.basics.Debug; import org.sikuli.basics.FileManager; import org.sikuli.script.Image; import org.sikuli.script.ImagePath; import org.sikuli.script.Runner; import org.sikuli.script.Sikulix; import org.sikuli.scriptrunner.ScriptingSupport; public class SikuliIDEPopUpMenu extends JPopupMenu { private static String me = "SikuliIDEPopUpMenu: "; private static int lvl = 3; private static void log(int level, String message, Object... args) { Debug.logx(level, me + message, args); } private String popType; private boolean validMenu = true; public static final String POP_TAB = "POP_TAB"; private CloseableTabbedPane refTab; public static final String POP_IMAGE = "POP_IMAGE"; private EditorPane refEditorPane = null; public static final String POP_LINE = "POP_LINE"; private EditorLineNumberView refLineNumberView = null; private static String[] selOptionsType = null; private MouseEvent mouseTrigger; private int menuCount = 0; private Map<String, Integer> menus = new HashMap<String, Integer>(); /** * Get the value of isValidMenu * * @return the value of isValidMenu */ public boolean isValidMenu() { return validMenu; } public SikuliIDEPopUpMenu(String pType, Object ref) { popType = pType; init(ref); } private void init(Object ref) { if (popType.equals(POP_TAB)) { refTab = (CloseableTabbedPane) ref; popTabMenu(); } else if (popType.equals(POP_IMAGE)) { refEditorPane = (EditorPane) ref; popImageMenu(); } else if (popType.equals(POP_LINE)) { refLineNumberView = (EditorLineNumberView) ref; popLineMenu(); } else { validMenu = false; } if (!validMenu) { return; } } public void doShow(CloseableTabbedPane comp, MouseEvent me) { mouseTrigger = me; show(comp, me.getX(), me.getY()); } private void fireIDEFileMenu(String name) throws NoSuchMethodException { fireIDEMenu(SikuliIDE.getInstance().getFileMenu(), name); } private void fireIDERunMenu(String name) throws NoSuchMethodException { fireIDEMenu(SikuliIDE.getInstance().getRunMenu(), name); } private void fireIDEMenu(JMenu menu, String name) throws NoSuchMethodException { JMenuItem jmi; String jmiName = null; for (int i = 0; i < menu.getItemCount(); i++) { jmi = menu.getItem(i); if (jmi == null || jmi.getName() == null) { continue; } jmiName = jmi.getName(); if (jmiName.equals(name)) { jmi.doClick(); } } if (jmiName == null) { log(-1, "IDEFileMenu not found: " + name); } } private void fireInsertTabAndLoad(int tabIndex) { SikuliIDE.FileAction insertNewTab = SikuliIDE.getInstance().getFileAction(tabIndex); insertNewTab.doInsert(null); } private JMenuItem createMenuItem(JMenuItem item, ActionListener listener) { item.addActionListener(listener); return item; } private JMenuItem createMenuItem(String name, ActionListener listener) { return createMenuItem(new JMenuItem(name), listener); } private void createMenuSeperator() { menuCount++; addSeparator(); } private void setMenuText(int index, String text) { ((JMenuItem) getComponent(index)).setText(text); } private String getMenuText(int index) { return ((JMenuItem) getComponent(index)).getText(); } private void setMenuEnabled(int index, boolean enabled) { ((JMenuItem) getComponent(index)).setEnabled(enabled); } class MenuAction implements ActionListener { protected Method actMethod = null; protected String action; protected int menuPos; public MenuAction() { } public MenuAction(String item) throws NoSuchMethodException { Class[] paramsWithEvent = new Class[1]; try { paramsWithEvent[0] = Class.forName("java.awt.event.ActionEvent"); actMethod = this.getClass().getMethod(item, paramsWithEvent); action = item; menuPos = menuCount++; menus.put(item, menuPos); } catch (ClassNotFoundException cnfe) { log(-1, "Can't find menu action: %s\n" + cnfe, item); } } @Override public void actionPerformed(ActionEvent e) { if (actMethod != null) { try { log(lvl, "PopMenuAction." + action); Object[] params = new Object[1]; params[0] = e; actMethod.invoke(this, params); } catch (Exception ex) { log(-1, "Problem when trying to invoke menu action %s\nError: %s", action, ex.getMessage()); } } } } private void popTabMenu() { try { add(createMenuItem("Set Type", new PopTabAction(PopTabAction.SET_TYPE))); createMenuSeperator(); add(createMenuItem("Move Tab", new PopTabAction(PopTabAction.MOVE_TAB))); add(createMenuItem("Duplicate", new PopTabAction(PopTabAction.DUPLICATE))); add(createMenuItem("Open", new PopTabAction(PopTabAction.OPEN))); add(createMenuItem("Open left", new PopTabAction(PopTabAction.OPENL))); createMenuSeperator(); add(createMenuItem("Save", new PopTabAction(PopTabAction.SAVE))); add(createMenuItem("SaveAs", new PopTabAction(PopTabAction.SAVE_AS))); createMenuSeperator(); add(createMenuItem("Run", new PopTabAction(PopTabAction.RUN))); add(createMenuItem("Run Slowly", new PopTabAction(PopTabAction.RUN_SLOW))); createMenuSeperator(); add(createMenuItem("Reset", new PopTabAction(PopTabAction.RESET))); } catch (NoSuchMethodException ex) { validMenu = false; } } class PopTabAction extends MenuAction { static final String SET_TYPE = "doSetType"; static final String MOVE_TAB = "doMoveTab"; static final String DUPLICATE = "doDuplicate"; static final String OPEN = "doOpen"; static final String OPENL = "doOpenLeft"; static final String SAVE = "doSave"; static final String SAVE_AS = "doSaveAs"; static final String RUN = "doRun"; static final String RUN_SLOW = "doRunSlow"; static final String RESET = "doReset"; public PopTabAction() { super(); } public PopTabAction(String item) throws NoSuchMethodException { super(item); } public void doSetType(ActionEvent ae) { //TODO use a popUpSelect for more language options Debug.log(3, "doSetType: selected"); String error = ""; EditorPane cp = SikuliIDE.getInstance().getCurrentCodePane(); if (selOptionsType == null) { Set<String> types = Runner.typeEndings.keySet(); selOptionsType = new String[types.size()]; int i = 0; for (String e : types) { if (e.contains("plain")) { continue; } selOptionsType[i++] = e.replaceFirst(".*?\\/", ""); } } String currentType = cp.getSikuliContentType(); String targetType = Sikulix.popSelect("Select the Scripting Language ...", selOptionsType, currentType.replaceFirst(".*?\\/", "")); if (targetType == null) { targetType = currentType; } else { targetType = "text/" + targetType; } if (currentType.equals(targetType)) { SikuliIDE.getStatusbar().setCurrentContentType(currentType); return; } String targetEnding = Runner.typeEndings.get(targetType); if (cp.getText().length() > 0) { // if (!cp.reparseCheckContent()) { if (!Sikulix.popAsk(String.format( "Switch to %s requested, but tab is not empty!\n" + "Click YES, to discard content and switch\n" + "Click NO to cancel this action and keep content.", targetType))) { error = ": with errors"; } } if (error.isEmpty()) { cp.reInit(targetEnding); // cp.setText(String.format(Settings.TypeCommentDefault, cp.getSikuliContentType())); cp.setText(""); error = ": (" + targetType + ")"; } String msg = "doSetType: completed" + error ; SikuliIDE.getStatusbar().setMessage(msg); SikuliIDE.getStatusbar().setCurrentContentType(targetType); Debug.log(3, msg); } public void doMoveTab(ActionEvent ae) throws NoSuchMethodException { if (ae.getActionCommand().contains("Insert")) { log(lvl, "doMoveTab: entered at insert"); doLoad(refTab.getSelectedIndex()+1); resetMenuAfterMoveTab(); return; } log(lvl, "doMoveTab: entered at move"); refTab.resetLastClosed(); if (SikuliIDE.getInstance().getCurrentCodePane().isSourceBundleTemp()) { log(-1, "Untitled tab cannot be moved"); return; } // fireIDEFileMenu("SAVE"); boolean success = refTab.fireCloseTab(mouseTrigger, refTab.getSelectedIndex()); if (success && refTab.getLastClosed() != null) { refTab.isLastClosedByMove = true; setMenuText(menus.get(MOVE_TAB), "Insert Right"); setMenuText(menus.get(OPENL), "Insert Left"); log(lvl, "doMoveTab: preparation success"); } else { log(-1, "doMoveTab: preperation aborted"); } } private void checkAndResetMoveTab() throws NoSuchMethodException { if (refTab.isLastClosedByMove) { log (-1, "doMoveTab: is prepared and will be aborted"); int currentTab = refTab.getSelectedIndex(); doLoad(refTab.getSelectedIndex()+1); refTab.setSelectedIndex(currentTab); } resetMenuAfterMoveTab(); } private void resetMenuAfterMoveTab() { setMenuText(menus.get(MOVE_TAB), "Move Tab"); setMenuText(menus.get(OPENL), "Open left"); refTab.resetLastClosed(); } public void doDuplicate(ActionEvent ae) throws NoSuchMethodException { log(lvl, "doDuplicate: entered"); EditorPane ep = SikuliIDE.getInstance().getCurrentCodePane(); checkAndResetMoveTab(); fireIDEFileMenu("SAVE"); if (ep.isSourceBundleTemp()) { log(-1, "Untitled tab cannot be duplicated"); return; } String bundleOld = ep.getBundlePath(); fireIDEFileMenu("SAVE_AS"); if (FileManager.pathEquals(bundleOld, ep.getBundlePath())) { log(-1,"duplicate must use different project name"); return; } setMenuText(menus.get(OPENL), "Insert left"); doOpenLeft(null); } private boolean doLoad(int tabIndex) { boolean success = true; fireInsertTabAndLoad(tabIndex); return success; } public void doOpen(ActionEvent ae) throws NoSuchMethodException { log(lvl, "doOpen: entered"); checkAndResetMoveTab(); doLoad(refTab.getSelectedIndex()+1); } public void doOpenLeft(ActionEvent ae) throws NoSuchMethodException { if (getMenuText(5).contains("Insert")) { log(lvl, "doOpenLeft: entered at insert left"); doLoad(refTab.getSelectedIndex()); resetMenuAfterMoveTab(); return; } log(lvl, "doOpenLeft: entered"); doLoad(refTab.getSelectedIndex()); } public void doSave(ActionEvent ae) throws NoSuchMethodException { log(lvl, "doSave: entered"); fireIDEFileMenu("SAVE"); } public void doSaveAs(ActionEvent ae) throws NoSuchMethodException { log(lvl, "doSaveAs: entered"); fireIDEFileMenu("SAVE_AS"); } public void doRun(ActionEvent ae) throws NoSuchMethodException { log(lvl, "doRun: entered"); fireIDERunMenu("RUN"); } public void doRunSlow(ActionEvent ae) throws NoSuchMethodException { log(lvl, "doRunSlow: entered"); fireIDERunMenu("RUN_SLOWLY"); } public void doReset(ActionEvent ae) throws NoSuchMethodException { log(lvl, "Reset: entered"); checkAndResetMoveTab(); Image.dump(lvl); ImagePath.reset(); Image.dump(lvl); SikuliIDE.getInstance().getCurrentCodePane().reparse(); } } private void popImageMenu() { try { add(createMenuItem("Preview", new PopImageAction(PopImageAction.PREVIEW))); } catch (NoSuchMethodException ex) { validMenu = false; } } class PopImageAction extends MenuAction { static final String PREVIEW = "doPreview"; public PopImageAction() { super(); } public PopImageAction(String item) throws NoSuchMethodException { super(item); } public void doPreview(ActionEvent ae) { log(lvl, "doPreview:"); } } private void popLineMenu() { try { add(createMenuItem("Action", new PopLineAction(PopLineAction.ACTION))); } catch (NoSuchMethodException ex) { validMenu = false; } } class PopLineAction extends MenuAction { static final String ACTION = "doAction"; public PopLineAction() { super(); } public PopLineAction(String item) throws NoSuchMethodException { super(item); } public void doAction(ActionEvent ae) { log(lvl, "doAction:"); } } }