package MaxFlowApplet.mf_gui; /* The paskage provides the interface for working with graphs, i.e. * * building them, and finding the maximal flow in a couple of manners */ import java.awt.*; import MaxFlowApplet.graphic.*; import MaxFlowApplet.graph.*; import MFApplet; /* The class creates a window for entering a data, by the user. The window * * has a field for typing, and keys for different actions. It works on an * * edge, and modifies the data in it, according to the user input and actions */ class EdgeInputDialog extends Dialog { private GraphFrame parent; GraphicEdge targetEdge; Graph currentGraph; private boolean inputNeeded; private Panel centerPanel; private Panel southPanel; private TextField inputField; private final static Label lbl = new Label("Enter new edge capacity:"); private final static Button deleteButton = new Button("Delete Edge"); private final static Button okButton = new Button(" OK "); private final static Button cancelButton = new Button("Cancel"); EdgeInputDialog(GraphicEdge modifiedEdge, Graph graph, GraphFrame f) { super (f, "Input", true); parent = (GraphFrame)f; parent.disable(); targetEdge = modifiedEdge; currentGraph = graph; this.setResizable(false); int curEdgeCapacity = targetEdge.getCapacity(); //if the capacity has illegal value, disable the "cancel" button //to approve, that a valid value will be entered if (curEdgeCapacity <= 0) { inputNeeded = true; cancelButton.disable(); } else { inputNeeded = false; cancelButton.enable(); } inputField = new TextField((new Integer(curEdgeCapacity)).toString(), 15); centerPanel = new Panel(); centerPanel.setLayout( new FlowLayout()); centerPanel.add(lbl); centerPanel.add(inputField); southPanel = new Panel(); southPanel.setLayout( new FlowLayout()); southPanel.add(okButton); southPanel.add(deleteButton); southPanel.add(cancelButton); this.setLayout( new BorderLayout()); this.add("Center", centerPanel); this.add("South", southPanel); this.resize(350, 125); this.show(); } public boolean handleEvent(Event e) { if ((e.id == Event.WINDOW_DESTROY)&&(!inputNeeded)) { removeInputDialog(); return true; } return super.handleEvent(e); } public boolean action( Event e, Object o) { int inputVal; if (e.target == okButton || e.target==inputField) { int inputValue; String input = inputField.getText(); if (input != null) { try { inputVal = Integer.parseInt(input); } catch (NumberFormatException except) { inputVal = targetEdge.getCapacity(); } if (inputVal > 0) { targetEdge.setCapacity(inputVal); removeInputDialog(); } } return true; } if (e.target == cancelButton) { removeInputDialog(); return true; } if (e.target == deleteButton) { currentGraph.removeEdge(targetEdge); removeInputDialog(); return true; } return true; } public void removeInputDialog() { hide(); parent.enable(); parent.appletCanvas.repaint(); dispose(); } } /* The class builds an info window (used for help for example). The window is * * not editable, but may be only read. It has a button for closing it and a * * field for displaying the info. */ class InfoDialog extends Dialog { private Button okButton = new Button(" OK "); private TextArea textSpace; GraphFrame parent; private Panel buttonPanel = new Panel(); InfoDialog( String s, String title, int width, int height, GraphFrame p) { super( p, title, true); parent = p; setLayout(new BorderLayout()); textSpace = new TextArea(s); textSpace.setFont(new Font("Courier", Font.PLAIN, 12)); textSpace.setEditable(false); buttonPanel.setLayout( new FlowLayout()); buttonPanel.add(okButton); add("South", buttonPanel); add("Center", textSpace); resize(height, width); show(); } public boolean handleEvent(Event e) { if (e.id == Event.WINDOW_DESTROY) { removeInfo(); return true; } return super.handleEvent(e); } public boolean action(Event e, Object o) { if (e.target == okButton) removeInfo(); return true; } public void removeInfo() { hide(); dispose(); parent.repaint(); } } /* That class is the working sheet for the user. On the canvas all the graph is * * drawn and most of the user actions are recieved by it. The most important * * functionality of the canvas is to respond on the mouse events, and draw the * * graph. */ public class GraphCanvas extends Canvas { public GraphCanvas (GraphFrame frame, Graph graph) { super(); setBackground(DEFAULTBACKGROUND); currentGraph = graph; pressedVertex = null; draggedVertex = null; waiting4drag = null; parentFrame = frame; //reading the trash image. it's done by a media tracker for insuring, that the //images are loaded before attempting to draw them. tracker = new MediaTracker(this); closedTrash = parentFrame.parentApplet.getImage(parentFrame.parentApplet.getDocumentBase(),"MaxFlowApplet/image/ClosedTrash.gif"); openedTrash = parentFrame.parentApplet.getImage(parentFrame.parentApplet.getDocumentBase(), "MaxFlowApplet/image/OpenTrash.gif"); tracker.addImage(closedTrash, 0); tracker.addImage(openedTrash, 1); try { tracker.waitForAll(); } catch (InterruptedException except) {} trashIcon = closedTrash; } // sets the greatest edge flow so when repainting every edge will have the right color // it doesn't repaint the graph protected void setGreatestEdgeFlow(int n) { if (n < 1) greatestEdgeFlow = DEFAULTEDGEFLOW; else greatestEdgeFlow = n; }; // returns true, when the point (x,y) is inside the trash image area private boolean insideTrash(int x, int y) { Dimension d = size(); return ((y>(d.height-trashIcon.getHeight(this)))&&(y(d.width-trashIcon.getWidth(this)))&&(x d.width) x = d.width; if (y < 0) y = 0; else if (y > d.height) y = d.height; // a vertex is already dragged, update its position if (draggedVertex != null) { draggedVertex.moveTo(x, y); if (insideTrash(x,y)) trashIcon = openedTrash; else trashIcon = closedTrash; } else if (waiting4drag != null) //there is a vertex that waits to be dragged if (dragCount < 3) dragCount++; else //the counter became high enough, start dragging the clicked vertex { dragCount = 0; draggedVertex = waiting4drag; draggedVertex.storeOriginalPosition(); waiting4drag = null; draggedVertex.press(); draggedVertex.moveTo(x, y); repaint(); } // end of start dragging the vertex else //if the event occured on a vertex, assign it as waiting for (int i=0; i < vertexNum; i++) { tmpVertex = (GraphicVertex)currentGraph.getVertex(i); if (tmpVertex.inside(x,y)) //the vertex on which the event occured is found //it will be assigned as waiting for dragging. If the drag //event appears enough times consequently, the vertex will //become dragged { dragCount++; waiting4drag = tmpVertex; } } repaint(); return true; } public boolean mouseUp(Event evt, int x, int y) { //if a vertex was dragged to the trash, remove it and all its edges dragCount = 0; trashIcon = closedTrash; if (draggedVertex != null) { if (insideTrash(x,y)) //can't delete the source and the sink if (((GraphicVertex)currentGraph.getSource() == draggedVertex)|| ((GraphicVertex)currentGraph.getSink() == draggedVertex)) { draggedVertex.moveToOriginalPosition(); draggedVertex.release(); } else currentGraph.removeVertex(draggedVertex); else { draggedVertex.release(); draggedVertex.draw(getGraphics()); } //if there was a vertex assigned as pressed, that is the dragged vertex itself //otherwise in mouseDown a edge would be created, and both verteces released draggedVertex = null; waiting4drag = null; if (pressedVertex != null); pressedVertex = null; repaint(); } return true; } public void repaint() { update(getGraphics()); } public void paint(Graphics g) { update(g); } // The method draw the graph and all the contents of the canvas // It works offscreen, till the picture is finished and then replaces // the current one with the new. public void update(Graphics g) { Dimension d = size(); int vertexNum = currentGraph.numberOfVertices(); int edgesNum = currentGraph.numberOfEdges(); GraphicVertex tmpVertex; GraphicEdge tmpEdge; int edgeFlow; int g_color; int b_color; if ((offscreen == null)||(d.width != offscreensize.width)|| (d.height != offscreensize.height)) { offscreen = createImage(d.width, d.height); offscreensize = d; offgraphics = offscreen.getGraphics(); offgraphics.setFont(getFont()); } offgraphics.setColor(getBackground()); offgraphics.fillRect(0, 0, d.width, d.height); //draw the trash icon offgraphics.drawImage(trashIcon, d.width-trashIcon.getWidth(this), d.height-trashIcon.getHeight(this), this); //drawing the edges for (int i=0; i= 2) //low flow in the edge tmpEdge.draw(offgraphics, new Color(0, 128 - (edgeFlow*255)/greatestEdgeFlow, 255)); else //high flow in the edge tmpEdge.draw(offgraphics, new Color(0, 0, 382 - (edgeFlow*255)/greatestEdgeFlow)); } // mark the augmenting path if the algorithm is executing if (markAugmentPath == true) { FlowVertex u; FlowVertex v; GraphicEdge e; v = (FlowVertex) currentGraph.getSink(); while (v != null) { u = v.getPredecessor(); if (u != null) { e = (GraphicEdge) u.getEdgeTo(v); if (e == null) e = (GraphicEdge) v.getEdgeTo(u); e.draw(offgraphics, AUGMENTPATHCOLOR); } v = u; } } // draw the vertices for (int i=0; i