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 017public class MemberTableLinkedCellRenderer extends MemberTableCellRenderer { 018 019 private static final Image arrowUp = ImageProvider.get("dialogs/relation", "arrowup").getImage(); 020 private static final Image arrowDown = ImageProvider.get("dialogs/relation", "arrowdown").getImage(); 021 private static final Image corners = ImageProvider.get("dialogs/relation", "roundedcorners").getImage(); 022 private static final Image roundabout_right = ImageProvider.get("dialogs/relation", "roundabout_right_tiny").getImage(); 023 private static final Image roundabout_left = ImageProvider.get("dialogs/relation", "roundabout_left_tiny").getImage(); 024 private transient WayConnectionType value = new WayConnectionType(); 025 026 @Override 027 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, 028 int row, int column) { 029 030 reset(); 031 if (value == null) 032 return this; 033 034 this.value = (WayConnectionType) value; 035 setToolTipText(((WayConnectionType) value).getToolTip()); 036 renderBackgroundForeground(getModel(table), null, isSelected); 037 return this; 038 } 039 040 @Override 041 public void paintComponent(Graphics g) { 042 super.paintComponent(g); 043 if (value == null || !value.isValid()) 044 return; 045 046 int ymax = this.getSize().height - 1; 047 int xloop = 10; 048 int xowloop = 0; 049 if (value.isOnewayLoopForwardPart) { 050 xowloop = -3; 051 } 052 if (value.isOnewayLoopBackwardPart) { 053 xowloop = 3; 054 } 055 056 int xoff = this.getSize().width / 2; 057 if (value.isLoop) { 058 xoff -= xloop / 2 - 1; 059 } 060 int w = 2; 061 int p = 2 + w + 1; 062 int y1 = 0; 063 int y2 = 0; 064 065 if (value.linkPrev) { 066 g.setColor(Color.black); 067 if (value.isOnewayHead) { 068 g.fillRect(xoff - 1, 0, 3, 1); 069 } else { 070 g.fillRect(xoff - 1 + xowloop, 0, 3, 1); 071 } 072 y1 = 0; 073 } else { 074 if (value.isLoop) { 075 g.setColor(Color.black); 076 y1 = 5; 077 g.drawImage(corners, xoff, y1-3, xoff+3, y1, 0, 0, 3, 3, new Color(0, 0, 0, 0), null); 078 g.drawImage(corners, xoff+xloop-2, y1-3, xoff+xloop+1, y1, 2, 0, 5, 3, new Color(0, 0, 0, 0), null); 079 g.drawLine(xoff+3, y1-3, xoff+xloop-3, y1-3); 080 } else { 081 g.setColor(Color.red); 082 if (value.isOnewayHead) { 083 g.drawRect(xoff-1, p - 3 - w, w, w); 084 } else { 085 g.drawRect(xoff-1 + xowloop, p - 1 - w, w, w); 086 } 087 y1 = p; 088 } 089 } 090 091 if (value.linkNext) { 092 g.setColor(Color.black); 093 if (value.isOnewayTail) { 094 g.fillRect(xoff - 1, ymax, 3, 1); 095 } else { 096 g.fillRect(xoff - 1 + xowloop, ymax, 3, 1); 097 } 098 y2 = ymax; 099 } else { 100 if (value.isLoop) { 101 g.setColor(Color.black); 102 y2 = ymax - 5; 103 g.fillRect(xoff-1, y2+2, 3, 3); 104 g.drawLine(xoff, y2, xoff, y2+2); 105 g.drawImage(corners, xoff+xloop-2, y2+1, xoff+xloop+1, y2+4, 2, 2, 5, 5, new Color(0, 0, 0, 0), null); 106 g.drawLine(xoff+3-1, y2+3, xoff+xloop-3, y2+3); 107 } else { 108 g.setColor(Color.red); 109 if (value.isOnewayTail) { 110 g.drawRect(xoff-1, ymax - p + 3, w, w); 111 } else { 112 g.drawRect(xoff-1 + xowloop, ymax - p + 1, w, w); 113 } 114 y2 = ymax - p; 115 } 116 } 117 118 /* vertical lines */ 119 g.setColor(Color.black); 120 if (value.isLoop) { 121 g.drawLine(xoff+xloop, y1, xoff+xloop, y2); 122 } 123 124 if (value.isOnewayHead) { 125 setDotted(g); 126 y1 = 7; 127 128 int[] xValues = {xoff - xowloop + 1, xoff - xowloop + 1, xoff}; 129 int[] yValues = {ymax, y1+1, 1}; 130 g.drawPolyline(xValues, yValues, 3); 131 unsetDotted(g); 132 g.drawLine(xoff + xowloop, y1+1, xoff, 1); 133 } 134 135 if (value.isOnewayTail) { 136 setDotted(g); 137 y2 = ymax - 7; 138 139 int[] xValues = {xoff+1, xoff - xowloop + 1, xoff - xowloop + 1}; 140 int[] yValues = {ymax-1, y2, y1}; 141 g.drawPolyline(xValues, yValues, 3); 142 unsetDotted(g); 143 g.drawLine(xoff + xowloop, y2, xoff, ymax-1); 144 } 145 146 if ((value.isOnewayLoopForwardPart || value.isOnewayLoopBackwardPart) && !value.isOnewayTail && !value.isOnewayHead) { 147 setDotted(g); 148 g.drawLine(xoff - xowloop+1, y1, xoff - xowloop+1, y2 + 1); 149 unsetDotted(g); 150 } 151 152 if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart) { 153 g.drawLine(xoff, y1, xoff, y2); 154 } 155 156 g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2); 157 158 /* special icons */ 159 Image arrow = null; 160 switch (value.direction) { 161 case FORWARD: 162 arrow = arrowDown; 163 break; 164 case BACKWARD: 165 arrow = arrowUp; 166 break; 167 } 168 if (value.direction == Direction.ROUNDABOUT_LEFT) { 169 g.drawImage(roundabout_left, xoff-6, 1, null); 170 } else if (value.direction == Direction.ROUNDABOUT_RIGHT) { 171 g.drawImage(roundabout_right, xoff-6, 1, null); 172 } 173 174 if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart && 175 (arrow != null)) { 176 g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null); 177 } 178 179 if (value.isOnewayLoopBackwardPart && value.isOnewayLoopForwardPart) { 180 if (arrow == arrowDown) { 181 arrow = arrowUp; 182 } else if (arrow == arrowUp) { 183 arrow = arrowDown; 184 } 185 } 186 187 if (arrow != null) { 188 g.drawImage(arrow, xoff+xowloop-3, (y1 + y2) / 2 - 2, null); 189 } 190 } 191 192 private static void setDotted(Graphics g) { 193 ((Graphics2D) g).setStroke(new BasicStroke( 194 1f, 195 BasicStroke.CAP_BUTT, 196 BasicStroke.CAP_BUTT, 197 5f, 198 new float[] {1f, 2f}, 199 0f)); 200 } 201 202 private static void unsetDotted(Graphics g) { 203 ((Graphics2D) g).setStroke(new BasicStroke()); 204 } 205}