/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.actions; import java.awt.event.ActionEvent; import java.util.LinkedList; import java.util.List; import javax.swing.Action; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import com.rapidminer.BreakpointListener; import com.rapidminer.Process; import com.rapidminer.ProcessListener; import com.rapidminer.gui.ConditionalAction; import com.rapidminer.gui.MainFrame; import com.rapidminer.gui.dnd.OperatorTransferHandler; import com.rapidminer.gui.flow.AutoWireThread; import com.rapidminer.gui.operatormenu.OperatorMenu; import com.rapidminer.gui.operatortree.actions.DeleteOperatorAction; import com.rapidminer.gui.operatortree.actions.InfoOperatorAction; import com.rapidminer.gui.operatortree.actions.SaveBuildingBlockAction; import com.rapidminer.gui.operatortree.actions.ToggleActivationItem; import com.rapidminer.gui.operatortree.actions.ToggleAllBreakpointsItem; import com.rapidminer.gui.operatortree.actions.ToggleBreakpointItem; import com.rapidminer.gui.processeditor.ProcessEditor; import com.rapidminer.gui.templates.NewBuildingBlockMenu; import com.rapidminer.gui.tools.EditBlockingProgressThread; import com.rapidminer.gui.tools.ResourceAction; import com.rapidminer.gui.tools.SwingTools; import com.rapidminer.operator.ExecutionUnit; import com.rapidminer.operator.IOContainer; import com.rapidminer.operator.Operator; import com.rapidminer.operator.OperatorChain; import com.rapidminer.operator.ProcessRootOperator; /** * A process editor that enables/disables actions depending * on the selection of operators. * * @author Simon Fischer, Tobias Malbrecht */ public class Actions implements ProcessEditor { public final Action INFO_OPERATOR_ACTION = new InfoOperatorAction() { private static final long serialVersionUID = 6758272768665592429L; @Override protected Operator getOperator() { return getFirstSelectedOperator(); } }; public final ToggleActivationItem TOGGLE_ACTIVATION_ITEM = new ToggleActivationItem(this); public final Action RENAME_OPERATOR_ACTION = new ResourceAction(true, "rename_in_processrenderer") { { setCondition(OPERATOR_SELECTED, MANDATORY); } private static final long serialVersionUID = -3104160320178045540L; @Override public void actionPerformed(ActionEvent e) { Operator operator = getFirstSelectedOperator(); String name = SwingTools.showInputDialog("rename_operator", operator.getName()); if (name != null && name.length() > 0) { operator.rename(name); } } }; public final Action NEW_OPERATOR_ACTION = new NewOperatorAction(this); public final Action NEW_BUILDING_BLOCK_ACTION = new NewBuildingBlockAction(this); public final Action SAVE_BUILDING_BLOCK_ACTION = new SaveBuildingBlockAction(this); // public final Action CUT_ACTION = new CutAction(this); // // public final Action COPY_ACTION = new CopyAction(this); // // public final Action PASTE_ACTION = new PasteAction(this); public final Action DELETE_OPERATOR_ACTION = new DeleteOperatorAction(this); public final ToggleBreakpointItem TOGGLE_BREAKPOINT[] = { new ToggleBreakpointItem(this, BreakpointListener.BREAKPOINT_BEFORE), new ToggleBreakpointItem(this, BreakpointListener.BREAKPOINT_AFTER) }; public transient final ToggleAllBreakpointsItem TOGGLE_ALL_BREAKPOINTS = new ToggleAllBreakpointsItem(this); public transient final Action MAKE_DIRTY_ACTION = new ResourceAction(true, "make_dirty") { private static final long serialVersionUID = -1260942717363137733L; { setCondition(OPERATOR_SELECTED, MANDATORY); } @Override public void actionPerformed(ActionEvent e) { for (Operator selectedOperator : new LinkedList<Operator>(getSelectedOperators())) { selectedOperator.makeDirty(); } } }; private List<Operator> selection; private Process process; // /** The current clip board, i.e. the selected operator before cut or copy was applied. */ // private transient List<Operator> clipBoard = null; private final MainFrame mainFrame; private final BreakpointListener breakpointListener = new BreakpointListener() { @Override public void breakpointReached(Process process, Operator op, IOContainer iocontainer, int location) { enableActions(); } @Override public void resume() { enableActions(); } }; private final ProcessListener processListener = new ProcessListener() { @Override public void processEnded(Process process) { enableActions(); mainFrame.RUN_ACTION.setState(process.getProcessState()); } @Override public void processFinishedOperator(Process process, Operator op) { } @Override public void processStartedOperator(Process process, Operator op) { } @Override public void processStarts(Process process) { enableActions(); } }; public Actions(MainFrame mainFrame) { this.mainFrame = mainFrame; // copyProperties(new ResourceActionAdapter("cut"), TransferHandler.getCutAction()); // copyProperties(new ResourceActionAdapter("copy"), TransferHandler.getCopyAction()); // copyProperties(new ResourceActionAdapter("paste"), TransferHandler.getPasteAction()); } /** Creates a new popup menu for the selected operator. */ public void addToOperatorPopupMenu(JPopupMenu menu, Action renameAction) { final Operator op = getFirstSelectedOperator(); final boolean singleSelection = getSelectedOperators().size() == 1; if (op != null && !singleSelection) { if (!(op instanceof ProcessRootOperator) && (op.getParent() != null) && op.getParent().isEnabled()) { // enable / disable operator menu.add(TOGGLE_ACTIVATION_ITEM.createMultipleActivationItem()); } } if (op != null && singleSelection) { menu.add(INFO_OPERATOR_ACTION); if (!(op instanceof ProcessRootOperator) && (op.getParent() != null) && op.getParent().isEnabled()) { // enable / disable operator menu.add(TOGGLE_ACTIVATION_ITEM.createMenuItem()); } if (renameAction != null) { menu.add(renameAction); } else { menu.add(RENAME_OPERATOR_ACTION); } menu.addSeparator(); } if ((op != null) && (op instanceof OperatorChain)) { menu.add(OperatorMenu.NEW_OPERATOR_MENU); } if ((op != null) && (!(op instanceof ProcessRootOperator)) && singleSelection) { if ((op instanceof OperatorChain) && (((OperatorChain) op).getAllInnerOperators().size() > 0)) { menu.add(OperatorMenu.REPLACE_OPERATORCHAIN_MENU); } else { menu.add(OperatorMenu.REPLACE_OPERATOR_MENU); } } // add building block menu if ((op != null) && (op instanceof OperatorChain)) { final NewBuildingBlockMenu buildingBlockMenu = new NewBuildingBlockMenu(this); menu.add(buildingBlockMenu); buildingBlockMenu.addMenuListener(new MenuListener() { public void menuCanceled(MenuEvent e) {} public void menuDeselected(MenuEvent e) {} public void menuSelected(MenuEvent e) { buildingBlockMenu.addAllMenuItems(); } }); } if ((op != null) && (!(op instanceof ProcessRootOperator))) { menu.add(SAVE_BUILDING_BLOCK_ACTION); } menu.addSeparator(); // menu.add(COPY_ACTION); // menu.add(CUT_ACTION); // menu.add(PASTE_ACTION); OperatorTransferHandler.installMenuItems(menu); menu.add(DELETE_OPERATOR_ACTION); menu.addSeparator(); if ((op != null) && singleSelection) { for (int i = 0; i < TOGGLE_BREAKPOINT.length; i++) { menu.add(TOGGLE_BREAKPOINT[i].createMenuItem()); } } menu.add(TOGGLE_ALL_BREAKPOINTS.createMenuItem()); // if ((op != null) && (!(op instanceof ProcessRootOperator)) && singleSelection) { // menu.add(MAKE_DIRTY_ACTION); // } } public Operator getFirstSelectedOperator() { if ((selection != null) && !selection.isEmpty()) { return selection.get(0); } else { return null; } } public List<Operator>getSelectedOperators() { return selection; } /** * Enables and disables all actions according to the current state * (process running, operator selected... */ public void enableActions() { if (SwingUtilities.isEventDispatchThread()) { enableActionsNow(); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { enableActionsNow(); } }); } updateCheckboxStates(); } private void enableActionsNow() { synchronized (process) { boolean[] currentStates = new boolean[ConditionalAction.NUMBER_OF_CONDITIONS]; Operator op = getFirstSelectedOperator(); if (op != null) { currentStates[ConditionalAction.OPERATOR_SELECTED] = true; if (op instanceof OperatorChain) currentStates[ConditionalAction.OPERATOR_CHAIN_SELECTED] = true; if (op.getParent() == null) { currentStates[ConditionalAction.ROOT_SELECTED] = true; } else { currentStates[ConditionalAction.PARENT_ENABLED] = op.getParent().isEnabled(); if (op.getExecutionUnit().getNumberOfOperators() > 1) { currentStates[ConditionalAction.SIBLINGS_EXIST] = true; } } } int processState = process.getProcessState(); currentStates[ConditionalAction.PROCESS_STOPPED] = processState == Process.PROCESS_STATE_STOPPED; currentStates[ConditionalAction.PROCESS_PAUSED] = processState == Process.PROCESS_STATE_PAUSED; currentStates[ConditionalAction.PROCESS_RUNNING] = processState == Process.PROCESS_STATE_RUNNING; currentStates[ConditionalAction.EDIT_IN_PROGRESS] = EditBlockingProgressThread.isEditing(); ConditionalAction.updateAll(currentStates); updateCheckboxStates(); } } // /** Cuts the currently selected operator into the clipboard. */ // public void cut() { // copy(); // delete(); // } // // /** Copies the currently selected operator into the clipboard. */ // public void copy() { // Operator selectedOperator = getSelectedOperator(); // if (selectedOperator != null) { // List<Operator> clones = new LinkedList<Operator>(); // for (Operator op : getSelectedOperators()) { // clones.add(op.cloneOperator(op.getName())); // } // clipBoard = clones; // enableActions(); // } // } // // /** Pastes the current clipboard into the tree. */ // public void paste() { // if (clipBoard != null) { // insert(clipBoard); // List<Operator> clones = new LinkedList<Operator>(); // for (Operator op : clipBoard) { // clones.add(op.cloneOperator(op.getName())); // } // clipBoard = clones; // } // enableActions(); // } /** The currently selected operator will be deleted. */ public void delete() { Operator parent = null; for (Operator selectedOperator : new LinkedList<Operator>(getSelectedOperators())) { if (parent == null) { parent = selectedOperator.getParent(); } selectedOperator.remove(); } mainFrame.selectOperator(parent); } /** The given operators will be inserted at the last position of the currently selected operator chain. */ public void insert(List<Operator> newOperators) { Object selectedNode = getSelectedOperator(); if (selectedNode == null) { SwingTools.showVerySimpleErrorMessage("cannot_insert_operator"); return; } else if ((selectedNode instanceof OperatorChain) && (((OperatorChain)selectedNode).getNumberOfSubprocesses() == 1)) { for (Operator newOperator : newOperators) { ((OperatorChain)selectedNode).getSubprocess(0).addOperator(newOperator); } } else { int i = 0; Operator selectedOperator = (Operator)selectedNode; ExecutionUnit process = selectedOperator.getExecutionUnit(); int parentIndex = process.getOperators().indexOf(selectedOperator) + 1; for (Operator newOperator : newOperators) { process.addOperator(newOperator, parentIndex + i); i++; } } AutoWireThread.autoWireInBackground(newOperators, true); mainFrame.selectOperators(newOperators); } public Operator getSelectedOperator() { return getFirstSelectedOperator(); } public Operator getRootOperator() { if (process != null) { return process.getRootOperator(); } return null; } public Process getProcess() { return process; } @Override public void processChanged(Process process) { if (this.process != process) { if (this.process != null) { this.process.removeBreakpointListener(breakpointListener); this.process.getRootOperator().removeProcessListener(processListener); } this.process = process; enableActions(); if (this.process != null) { this.process.addBreakpointListener(breakpointListener ); this.process.getRootOperator().addProcessListener(processListener); } } } @Override public void processUpdated(Process process) { enableActions(); } @Override public void setSelection(List<Operator> selection) { this.selection = selection; enableActions(); } private void updateCheckboxStates() { Operator op = getSelectedOperator(); if (op != null) { for (int pos = 0; pos < TOGGLE_BREAKPOINT.length; pos++) { TOGGLE_BREAKPOINT[pos].setSelected(op.hasBreakpoint(pos)); } TOGGLE_ACTIVATION_ITEM.setSelected(op.isEnabled()); } } }