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