/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package robotinterface.gui.panels; import java.awt.BasicStroke; import java.awt.Color; import robotinterface.gui.panels.sidepanel.SidePanel; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Stack; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import robotinterface.algorithm.Command; import robotinterface.algorithm.GraphicFlowchart; import robotinterface.algorithm.procedure.Block; import robotinterface.algorithm.procedure.DummyBlock; import robotinterface.algorithm.procedure.Function; import robotinterface.algorithm.procedure.Function.FunctionEnd; import robotinterface.algorithm.procedure.If; import robotinterface.algorithm.procedure.Procedure; import robotinterface.drawable.Drawable; import robotinterface.drawable.GraphicObject; import robotinterface.drawable.DrawingPanel; import robotinterface.drawable.swing.WidgetContainer; import robotinterface.drawable.graphicresource.GraphicResource; import robotinterface.drawable.util.QuickFrame; import robotinterface.gui.panels.sidepanel.Item; import robotinterface.interpreter.Interpreter; import robotinterface.plugin.PluginManager; /** * * @author antunes */ public class FlowchartPanel extends DrawingPanel implements Interpertable { private final Color selectionColor = new Color(0, .2f, .5f, .5f); private final Color executionColor = new Color(0, 1, 0, .5f); private final Color errorColor = new Color(1, 0, 0, .5f); public ArrayList<JPanel> tabs = new ArrayList<>(); private final ArrayList<Command> selection = new ArrayList<>(); private final ArrayList<Command> copy = new ArrayList<>(); private final Stack<Function> undo = new Stack<>(); private final Stack<Function> redo = new Stack<>(); private final SidePanel sidePanel; private final Interpreter interpreter; private Function function; private boolean keyActionUsed = false; private Command newCommand = null; private Item itemSelected = null; private int clickDrop = 0; private GraphicObject executionCommand = null; public FlowchartPanel(Function function, final Interpreter interpreter) { sidePanel = new SidePanel() { @Override protected void ItemSelected(Item item, Object ref) { if (interpreter.getInterpreterState() == Interpreter.PLAY) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(null, "Atenção: A edição do fluxograma está suspensa\naté que o código termine ou seja pausado.", "Atenção", JOptionPane.WARNING_MESSAGE); if (itemSelected != null) { itemSelected.setSelected(false); itemSelected = null; } } }); } try { if (itemSelected != null) { itemSelected.setSelected(false); } itemSelected = item; itemSelected.setSelected(true); newCommand = SidePanel.newInstance(ref); } catch (Exception ex) { ex.printStackTrace(); } } }; sidePanel.setColor(Color.decode("#54A4A4")); sidePanel.addAllClasses(PluginManager.getPluginsAlpha("robotinterface/algorithm/plugin.txt", Procedure.class)); sidePanel.addAllClasses(PluginManager.getPluginsAlpha("robotinterface/plugin/cmdpack/plugin.txt", Procedure.class)); add(sidePanel); this.interpreter = interpreter; if (!interpreter.isAlive()) { this.interpreter.start(); } setFunction(function); super.setName("Fluxograma"); gridSize = -10; gridColor = new Color(0.95f, 0.95f, 0.95f); } public void hideSidePanel(boolean b) { sidePanel.setOpen(!b); } @Override public Interpreter getInterpreter() { return interpreter; } public Function getFunction() { return function; } public final void setFunction(Function function) { removeGraphicResources(this.function); this.function = function; ident(function); setName(function.toString()); interpreter.setInterpreterState(Interpreter.STOP); interpreter.setMainFunction(function); } public void ident(Function f) { addDummyBlocks(function, this); ident(function, true); addAllDrawableResources(function, this); } private static void addDummyBlocks(Command c, FlowchartPanel fp) { if (c instanceof Block) { Block b = (Block) c; if (b.size() == 1) { //só tem o EndBlock DummyBlock db = new DummyBlock(); b.add(db); } Command it = b.getStart(); while (it != null) { addDummyBlocks(it, fp); if (it instanceof DummyBlock) { //confirma if (it.getParent() instanceof Block) { if (((Block) it.getParent()).size() > 2) { fp.removeGraphicResources(it); } } } it = it.getNext(); } } else if (c instanceof If) { addDummyBlocks(((If) c).getBlockTrue(), fp); addDummyBlocks(((If) c).getBlockFalse(), fp); } } private static void hideAllWidgets(Command c, Command ign) { if (c != ign) { GraphicObject go = c.getDrawableResource(); if (go != null) { if (go instanceof WidgetContainer) { ((WidgetContainer) go).setWidgetVisible(false); } } } if (c instanceof Block) { Block b = (Block) c; if (b.size() == 1) { //só tem o EndBlock DummyBlock db = new DummyBlock(); b.add(db); } Command it = b.getStart(); while (it != null) { hideAllWidgets(it, ign); it = it.getNext(); } } else if (c instanceof If) { hideAllWidgets(((If) c).getBlockTrue(), ign); hideAllWidgets(((If) c).getBlockFalse(), ign); } } private static void ident(Function f, boolean b) { f.ident(GraphicFlowchart.GF_X, GraphicFlowchart.GF_Y, GraphicFlowchart.GF_J, GraphicFlowchart.GF_K); } private boolean addCommand(Point p) { Command c = function.find(p); if (c != null) { boolean addNext = true; if (c instanceof FunctionEnd) { if (c.getPrevious() != null) { c = c.getPrevious(); } else { c = c.getParent(); } } //(***) descomentar para adicionar blocos antes //se clicado na parte superior da seleção if (c instanceof Function) { c = ((Function) c).get(0); addNext = false; //(***) } if (c instanceof GraphicResource) { //(***) GraphicObject d = ((GraphicResource) c).getDrawableResource(); if (d != null) { //g.draw(d.getObjectShape()); //alterar usando fIx e fIy if (c instanceof DummyBlock || p.y > d.getObjectBouds().getCenterY()) { addNext = true; } else { addNext = false; } } } Command n = newCommand; if (n instanceof GraphicResource) { GraphicObject d = ((GraphicResource) n).getDrawableResource(); if (d != null) { this.add(d); } } pushUndo(); redo.clear(); interpreter.setInterpreterState(Interpreter.STOP); if (addNext) { c.addAfter(newCommand); } else { c.addBefore(newCommand); } if (c instanceof DummyBlock) { removeGraphicResources(c); } selection.clear(); selection.add(newCommand); ident(function); return true; } return false; } @Override public void drawTopLayer(Graphics2D g, GraphicAttributes ga, InputState in) { Command cmd = interpreter.getCurrentCommand(); if (interpreter.getInterpreterState() == Interpreter.STOP) { executionCommand = null; // } else if (interpreter.getTimestep() < 20) { // executionCommand = interpreter.getMainFunction().getDrawableResource(); } else { if (cmd instanceof GraphicResource) { GraphicObject d = ((GraphicResource) cmd).getDrawableResource(); if (d != null && cmd != function) { executionCommand = d; } } } Command error = interpreter.getErrorCommand(); if (error != null) { GraphicObject errorCommand = ((GraphicResource) error).getDrawableResource(); AffineTransform o = g.getTransform(); AffineTransform n = ga.getT(o); ga.applyGlobalPosition(n); ga.applyZoom(n); g.setTransform(n); g.setColor(errorColor); g.setStroke(new BasicStroke(5)); g.fill(errorCommand.getObjectShape()); g.draw(errorCommand.getObjectShape()); g.setTransform(o); ga.done(n); } else if (executionCommand != null) { AffineTransform o = g.getTransform(); AffineTransform n = ga.getT(o); ga.applyGlobalPosition(n); ga.applyZoom(n); g.setTransform(n); g.setColor(executionColor); g.setStroke(new BasicStroke(5)); g.fill(executionCommand.getObjectShape()); g.draw(executionCommand.getObjectShape()); g.setTransform(o); ga.done(n); } if (newCommand != null) { if (itemSelected != null) { g.translate(in.getMouse().x - 10, in.getMouse().y - 10); g.setColor(itemSelected.getColor()); g.fill(itemSelected.getIcon()); } if (in.mouseGeneralClick()) { if (in.getMouseButton() == MouseEvent.BUTTON1) { clickDrop++; if (clickDrop == 2) { Point p = in.getTransformedMouse(); //tenta adicionar na posição do mouse if (!addCommand(p)) { //tenta adicionar 15 px para baixo p.y += 15; if (!addCommand(p)) { //tenta adicionar 15 px para cima p.y -= 30; if (!addCommand(p)) { } } } newCommand = null; itemSelected.setSelected(false); itemSelected = null; clickDrop = 0; } } else { newCommand = null; itemSelected.setSelected(false); itemSelected = null; clickDrop = 0; } } } } public void addAllDrawableResources(Command c, DrawingPanel p) { GraphicObject d = ((GraphicResource) c).getDrawableResource(); add(d); //com verificação null e contains if (c instanceof Block) { Block b = (Block) c; Command it = b.getStart(); while (it != null) { addAllDrawableResources(it, p); it = it.getNext(); } } else if (c instanceof If) { addAllDrawableResources(((If) c).getBlockTrue(), p); addAllDrawableResources(((If) c).getBlockFalse(), p); } } @Override public int getDrawableLayer() { return Drawable.BACKGROUND_LAYER | Drawable.DEFAULT_LAYER | Drawable.TOP_LAYER; } private void printBounds(Graphics2D g, Command c) { Rectangle2D.Double bounds = c.getBounds(null, GraphicFlowchart.GF_J, GraphicFlowchart.GF_K); g.draw(bounds); g.drawString(c.getCommandName(), (int) bounds.getMaxX(), (int) bounds.y); if (c instanceof Block) { Block b = (Block) c; Command it = b.getStart(); while (it != null) { printBounds(g, it); it = it.getNext(); } } else if (c instanceof If) { printBounds(g, ((If) c).getBlockTrue()); printBounds(g, ((If) c).getBlockFalse()); } } private void drawSelectedCommand(Graphics2D g, Command c) { if (c instanceof GraphicResource && c.getParent() != null) { GraphicObject d = ((GraphicResource) c).getDrawableResource(); if (d != null) { g.setColor(selectionColor); if (d instanceof WidgetContainer) { WidgetContainer wc = (WidgetContainer) d; if (!wc.isWidgetVisible()) { g.fill(d.getObjectShape()); } g.draw(d.getObjectShape()); } else { g.fill(d.getObjectShape()); g.draw(d.getObjectShape()); } } } if (c instanceof Block) { Block b = (Block) c; Command it = b.getStart(); while (it != null) { drawSelectedCommand(g, it); it = it.getNext(); } } else if (c instanceof If) { drawSelectedCommand(g, ((If) c).getBlockTrue()); drawSelectedCommand(g, ((If) c).getBlockFalse()); } } private void drawSelection(Graphics2D g) { g.setStroke(BOLD_STROKE); for (Command c : selection) { drawSelectedCommand(g, c); } } @Override public void draw(Graphics2D g, GraphicAttributes ga, InputState in) { ident(function); // g.setStroke(DEFAULT_STROKE); // g.setColor(Color.MAGENTA); // printBounds(g, function); drawSelection(g); if (in.isKeyPressed(KeyEvent.VK_DELETE) && !selection.isEmpty()) { pushUndo(); redo.clear(); for (Command c : selection) { if (!(c instanceof FunctionEnd)) { removeGraphicResources(c); } } selection.clear(); ident(function); } if (in.isKeyPressed(KeyEvent.VK_CONTROL)) { if (!keyActionUsed) { if (in.isKeyPressed(KeyEvent.VK_Z)) { undo(); keyActionUsed = true; } if (in.isKeyPressed(KeyEvent.VK_Y)) { redo(); keyActionUsed = true; } if (in.isKeyPressed(KeyEvent.VK_X)) { if (isValidSelection()) { copy.clear(); pushUndo(); redo.clear(); for (Command c : selection) { if (c instanceof Procedure) { Procedure p = (Procedure) c; copy.add(p.copy((Procedure) p.createInstance())); removeGraphicResources(c); } else if (!(c instanceof FunctionEnd)) { System.out.println("Erro de copia " + c); } } selection.clear(); ident(function); } keyActionUsed = true; } if (in.isKeyPressed(KeyEvent.VK_C)) { if (isValidSelection()) { copy.clear(); for (Command c : selection) { if (c instanceof Procedure) { Procedure p = (Procedure) c; copy.add(p.copy((Procedure) p.createInstance())); } else if (!(c instanceof FunctionEnd)) { System.out.println("Erro de copia " + c); } } } keyActionUsed = true; } if (in.isKeyPressed(KeyEvent.VK_V)) { if (!selection.isEmpty() && !copy.isEmpty()) { pushUndo(); Command s = selection.get(0); selection.clear(); for (Command c : copy) { if (c instanceof Procedure) { Procedure p = (Procedure) c; c = p.copy((Procedure) p.createInstance()); } s.addAfter(c); addAllDrawableResources(c, this); selection.add(c); s = c; } ident(function); } keyActionUsed = true; } } } if (in.numberOfKeysPressed() <= 1) { keyActionUsed = false; } if (in.mouseGeneralClick() && in.getMouseButton() == MouseEvent.BUTTON1) { Point p = in.getTransformedMouse(); Command c = function.find(p); hideAllWidgets(function, c); if (c != null) { GraphicObject go = c.getDrawableResource(); boolean ignore = false; if (go != null) { if (go instanceof WidgetContainer) { ignore = ((WidgetContainer) go).isWidgetVisible(); } } if (ignore) { selection.clear(); } else if (in.isKeyPressed(KeyEvent.VK_CONTROL)) { if (selection.contains(c)) { selection.remove(c); } else { //selection.add(0, c); addToSelection(c); } } else if (!selection.contains(c) && in.isKeyPressed(KeyEvent.VK_SHIFT)) { //organizar seleção if (!selection.isEmpty()) { Command start = selection.get(0); boolean ok = false; Command it = start; while (it != null) { if (!selection.contains(it)) { addToSelection(it); } it = it.getNext(); if (it == c) { ok = true; break; } } if (!ok) { selection.clear(); it = start; while (it != null) { if (!selection.contains(it)) { addToSelection(it); } it = it.getPrevious(); if (it == c) { ok = true; break; } } if (!ok) { //procurar para cima e para baixo :( agora não selection.clear(); } } } addToSelection(c); } else { if (selection.contains(c)) { selection.clear(); } else { selection.clear(); addToSelection(c); } } } else if (in.getSingleKey() == 0) { selection.clear(); } } } private void addToSelection(Command c) { //verifica se estão no mesmo bloco int clevel = c.getLevel(); Command cparent = c.getParent(); for (Command i : selection) { if (i.getParent() != cparent || c.getLevel() != clevel) { return; } } selection.add(c); } private void removeGraphicResources(Command c) { if (c == null) { return; } if (c instanceof Block) { Command it = ((Block) c).getStart(); while (it != null) { removeGraphicResources(it); it = it.getNext(); } } else if (c instanceof If) { removeGraphicResources(((If) c).getBlockTrue()); removeGraphicResources(((If) c).getBlockFalse()); } super.remove(c.getDrawableResource()); if (c.getParent() instanceof Block && c == ((Block) c.getParent()).getStart()) { ((Block) c.getParent()).shiftStart(); } c.remove(); } private boolean isValidSelection() { if (selection.isEmpty()) { return false; } Command start, end; start = selection.get(0); while (selection.contains(start.getPrevious())) { start = start.getPrevious(); } end = start; int i = 1; while (selection.contains(end.getNext())) { i++; end = end.getNext(); } if (i == selection.size()) { selection.clear(); Command it = start; while (it != end.getNext()) { selection.add(it); it = it.getNext(); } return true; } return false; } public static void main(String[] args) { QuickFrame.applyLookAndFeel(); FlowchartPanel p = new FlowchartPanel(Interpreter.newTestFunction(), new Interpreter()); QuickFrame.create(p, "Teste FlowcharPanel").addComponentListener(p); } public void pushUndo() { undo.add(function.copy()); if (redo.size() > 10) { undo.remove(10); } } private void pushRedo() { redo.add(function.copy()); if (redo.size() > 10) { redo.remove(10); } } public void undo() { if (undo.size() > 0) { pushRedo(); setFunction(undo.pop()); selection.clear(); } } public void redo() { if (redo.size() > 0) { pushUndo(); setFunction(redo.pop()); selection.clear(); } } }