001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.relation; 003 004import java.awt.BasicStroke; 005import java.awt.Color; 006import java.awt.Component; 007import java.awt.Graphics; 008import java.awt.Graphics2D; 009import java.awt.Image; 010 011import javax.swing.JTable; 012 013import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType; 014import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction; 015import org.openstreetmap.josm.tools.ImageProvider; 016 017/** 018 * This class renders the link column of the member table. It shows if the way segments are connected or not. 019 */ 020public class MemberTableLinkedCellRenderer extends MemberTableCellRenderer { 021 022 private static final Image ARROW_UP = ImageProvider.get("dialogs/relation", "arrowup").getImage(); 023 private static final Image ARROW_DOWN = ImageProvider.get("dialogs/relation", "arrowdown").getImage(); 024 private static final Image CORNERS = ImageProvider.get("dialogs/relation", "roundedcorners").getImage(); 025 private static final Image ROUNDABOUT_RIGHT = ImageProvider.get("dialogs/relation", "roundabout_right_tiny").getImage(); 026 private static final Image ROUNDABOUT_LEFT = ImageProvider.get("dialogs/relation", "roundabout_left_tiny").getImage(); 027 private transient WayConnectionType value = new WayConnectionType(); 028 029 @Override 030 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, 031 int row, int column) { 032 033 reset(); 034 if (value != null) { 035 this.value = (WayConnectionType) value; 036 setToolTipText(((WayConnectionType) value).getTooltip()); 037 renderBackgroundForeground(getModel(table), null, isSelected); 038 } 039 return this; 040 } 041 042 @Override 043 public void paintComponent(Graphics g) { 044 super.paintComponent(g); 045 if (value == null || !value.isValid()) 046 return; 047 048 int ymax = this.getSize().height - 1; 049 int xloop = 10; 050 int xowloop = 0; 051 if (value.isOnewayLoopForwardPart) { 052 xowloop = -3; 053 } 054 if (value.isOnewayLoopBackwardPart) { 055 xowloop = 3; 056 } 057 058 int xoff = this.getSize().width / 2; 059 if (value.isLoop) { 060 xoff -= xloop / 2 - 1; 061 } 062 int w = 2; 063 int p = 2 + w + 1; 064 int y1 = computePreviousY(g, xloop, xowloop, xoff, w, p); 065 int y2 = computeNextY(g, ymax, xloop, xowloop, xoff, w, p); 066 067 /* vertical lines */ 068 if (value.onewayFollowsNext && value.onewayFollowsPrevious) { 069 // foreground is set via renderBackgroundForeground 070 g.setColor(getForeground()); 071 } else { 072 g.setColor(getForeground().brighter()); 073 } 074 if (value.isLoop) { 075 g.drawLine(xoff+xloop, y1, xoff+xloop, y2); 076 } 077 078 if (value.isOnewayHead) { 079 setDotted(g); 080 y1 = 7; 081 082 int[] xValues = {xoff - xowloop + 1, xoff - xowloop + 1, xoff}; 083 int[] yValues = {ymax, y1+1, 1}; 084 g.drawPolyline(xValues, yValues, 3); 085 unsetDotted(g); 086 g.drawLine(xoff + xowloop, y1+1, xoff, 1); 087 } 088 089 if (value.isOnewayTail) { 090 setDotted(g); 091 y2 = ymax - 7; 092 093 int[] xValues = {xoff+1, xoff - xowloop + 1, xoff - xowloop + 1}; 094 int[] yValues = {ymax-1, y2, y1}; 095 g.drawPolyline(xValues, yValues, 3); 096 unsetDotted(g); 097 g.drawLine(xoff + xowloop, y2, xoff, ymax-1); 098 } 099 100 if ((value.isOnewayLoopForwardPart || value.isOnewayLoopBackwardPart) && !value.isOnewayTail && !value.isOnewayHead) { 101 setDotted(g); 102 g.drawLine(xoff - xowloop+1, y1, xoff - xowloop+1, y2 + 1); 103 unsetDotted(g); 104 } 105 106 if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart) { 107 g.drawLine(xoff, y1, xoff, y2); 108 } 109 110 g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2); 111 112 /* special icons */ 113 Image arrow = getArrow(); 114 if (value.direction == Direction.ROUNDABOUT_LEFT) { 115 g.drawImage(ROUNDABOUT_LEFT, xoff-6, 1, null); 116 } else if (value.direction == Direction.ROUNDABOUT_RIGHT) { 117 g.drawImage(ROUNDABOUT_RIGHT, xoff-6, 1, null); 118 } 119 120 if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart && 121 (arrow != null)) { 122 g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null); 123 } 124 125 if (value.isOnewayLoopBackwardPart && value.isOnewayLoopForwardPart) { 126 if (arrow == ARROW_DOWN) { 127 arrow = ARROW_UP; 128 } else if (arrow == ARROW_UP) { 129 arrow = ARROW_DOWN; 130 } 131 } 132 133 if (arrow != null) { 134 g.drawImage(arrow, xoff+xowloop-3, (y1 + y2) / 2 - 2, null); 135 } 136 } 137 138 private int computePreviousY(Graphics g, int xloop, int xowloop, int xoff, int w, int p) { 139 int y1; 140 141 if (value.linkPrev) { 142 if (value.onewayFollowsPrevious) { 143 g.setColor(getForeground()); 144 } else { 145 g.setColor(getForeground().brighter()); 146 } 147 if (value.isOnewayHead) { 148 g.fillRect(xoff - 1, 0, 3, 1); 149 } else { 150 g.fillRect(xoff - 1 + xowloop, 0, 3, 1); 151 } 152 y1 = 0; 153 } else { 154 if (value.isLoop) { 155 g.setColor(getForeground()); 156 y1 = 5; 157 g.drawImage(CORNERS, xoff, y1-3, xoff+3, y1, 0, 0, 3, 3, new Color(0, 0, 0, 0), null); 158 g.drawImage(CORNERS, xoff+xloop-2, y1-3, xoff+xloop+1, y1, 2, 0, 5, 3, new Color(0, 0, 0, 0), null); 159 g.drawLine(xoff+3, y1-3, xoff+xloop-3, y1-3); 160 } else { 161 g.setColor(Color.red); 162 if (value.isOnewayHead) { 163 g.drawRect(xoff-1, p - 3 - w, w, w); 164 } else { 165 g.drawRect(xoff-1 + xowloop, p - 1 - w, w, w); 166 } 167 y1 = p; 168 } 169 } 170 return y1; 171 } 172 173 private int computeNextY(Graphics g, int ymax, int xloop, int xowloop, int xoff, int w, int p) { 174 int y2; 175 176 if (value.linkNext) { 177 if (value.onewayFollowsNext) { 178 g.setColor(getForeground()); 179 } else { 180 g.setColor(getForeground().brighter()); 181 } 182 if (value.isOnewayTail) { 183 g.fillRect(xoff - 1, ymax, 3, 1); 184 } else { 185 g.fillRect(xoff - 1 + xowloop, ymax, 3, 1); 186 } 187 y2 = ymax; 188 } else { 189 if (value.isLoop) { 190 g.setColor(getForeground()); 191 y2 = ymax - 5; 192 g.fillRect(xoff-1, y2+2, 3, 3); 193 g.drawLine(xoff, y2, xoff, y2+2); 194 g.drawImage(CORNERS, xoff+xloop-2, y2+1, xoff+xloop+1, y2+4, 2, 2, 5, 5, new Color(0, 0, 0, 0), null); 195 g.drawLine(xoff+3-1, y2+3, xoff+xloop-3, y2+3); 196 } else { 197 g.setColor(Color.red); 198 if (value.isOnewayTail) { 199 g.drawRect(xoff-1, ymax - p + 3, w, w); 200 } else { 201 g.drawRect(xoff-1 + xowloop, ymax - p + 1, w, w); 202 } 203 y2 = ymax - p; 204 } 205 } 206 return y2; 207 } 208 209 private Image getArrow() { 210 if (!value.ignoreOneway) { 211 switch (value.direction) { 212 case FORWARD: 213 return ARROW_DOWN; 214 case BACKWARD: 215 return ARROW_UP; 216 default: 217 break; 218 } 219 } 220 return null; 221 } 222 223 private static void setDotted(Graphics g) { 224 ((Graphics2D) g).setStroke(new BasicStroke( 225 1f, 226 BasicStroke.CAP_BUTT, 227 BasicStroke.JOIN_MITER, 228 5f, 229 new float[] {1f, 2f}, 230 0f)); 231 } 232 233 private static void unsetDotted(Graphics g) { 234 ((Graphics2D) g).setStroke(new BasicStroke()); 235 } 236}