/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cassandra.contrib.circuit; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.geom.Ellipse2D; import java.awt.geom.RoundRectangle2D; import javax.swing.*; import java.io.IOException; import java.net.URL; import java.util.Enumeration; import java.util.List; public class RingPanel extends JPanel { private static final long serialVersionUID = 1L; private static final Color bgColor = Color.white; private static final String nodeImageFileOk = "images/node_green30x30.png"; private static final String nodeImageFileSeed = "images/node_blue30x30.png"; private static final String nodeImageFileShort = "images/node_red30x30.png"; private static final String nodeImageFileUnknown = "images/node_yellow30x30.png"; private static final Color ringColor = Color.blue; private static final Color fontColor = Color.black; private static final String fontName = "Helvetica"; private static final int fontSize = 12; private static final int padding = 70; private static final int nodeDiameter = 30; private static final char[] verificationMessage = "Verifying ring...".toCharArray(); private static RenderingHints defaultHints; private static Image nodeImageOk, nodeImageSeed, nodeImageShort, nodeImageUnknown; private RingModel ringModel; private boolean isVerifying = false; static { defaultHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); defaultHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); } public RingPanel(RingModel ringModel) { setBackground(bgColor); setFont(new Font(fontName, Font.PLAIN, fontSize)); this.ringModel = ringModel; nodeImageOk = new ImageIcon(getClass().getClassLoader().getResource(nodeImageFileOk)).getImage(); nodeImageSeed = new ImageIcon(getClass().getClassLoader().getResource(nodeImageFileSeed)).getImage(); nodeImageShort = new ImageIcon(getClass().getClassLoader().getResource(nodeImageFileShort)).getImage(); nodeImageUnknown = new ImageIcon(getClass().getClassLoader().getResource(nodeImageFileUnknown)).getImage(); } public void paintComponent(Graphics g) { clear(g); Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHints(defaultHints); // Draw the ring g2d.setPaint(ringColor); g2d.setStroke(new BasicStroke(1)); int dia = getWidth() > getHeight() ? getHeight() - padding : getWidth() - padding; int radius = dia / 2; double ringX = (getWidth() / 2) - radius; double ringY = (getHeight() / 2) - radius; Ellipse2D.Double ring = new Ellipse2D.Double(ringX, ringY, dia, dia); g2d.draw(ring); // Obtain the ring according to our seed List<Node> nodes = ringModel.getNodes(); // Place the nodes around the ring double current = 0; double increment = (2 * Math.PI) / nodes.size(); // Draw each node for (Node node : nodes) { Image nodeImage = null; switch (node.nodeStatus) { case ISSEED: nodeImage = nodeImageSeed; break; case OK: nodeImage = nodeImageOk; break; case SHORT: case LONG: nodeImage = nodeImageShort; break; case UNKNOWN: nodeImage = nodeImageUnknown; break; } double x = Math.cos(current) * radius + (ring.getCenterX() - (nodeDiameter / 2)); double y = Math.sin(current) * radius + (ring.getCenterY() - (nodeDiameter / 2)); current = current + increment; g2d.drawImage(nodeImage, (int)x, (int)y, null); // Draw a square with rounded corners around the node to indicate // when it is "selected", or active. if (node.isSelected()) { g2d.setPaint(ringColor); RoundRectangle2D.Double outline = new RoundRectangle2D.Double( (x - 2), (y - 2), (nodeDiameter + 4), (nodeDiameter + 4), 10, 10); g2d.draw(outline); } // Write the label; g2d.setPaint(fontColor); g2d.drawString(node.getHost(), (int)x - (nodeDiameter / 2), (int)y - 5); } // if we're in the middle of verifying, draw something to indicate we are doing that. if (isVerifying) { int msgWidth = g2d.getFontMetrics().charsWidth(verificationMessage, 0, verificationMessage.length); g2d.setColor(new Color(128, 128, 128, 128)); g2d.fillRect(0, 0, getWidth(), getHeight()); g2d.setColor(fontColor); g2d.drawChars(verificationMessage, 0, verificationMessage.length, getWidth()/2 - msgWidth/2, getHeight()/2); } } public void setVerifying(boolean b) { if (b != isVerifying) { isVerifying = b; SwingUtilities.invokeLater(new Runnable() {public void run() { repaint(); }}); } } // super.paintComponent clears offscreen pixmap, // since we're using double buffering by default. protected void clear(Graphics g) { super.paintComponent(g); } }