001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.dialogs.relation;
003    
004    import java.awt.BasicStroke;
005    import java.awt.Color;
006    import java.awt.Component;
007    import java.awt.Graphics;
008    import java.awt.Graphics2D;
009    import java.awt.Image;
010    
011    import javax.swing.JTable;
012    
013    import org.openstreetmap.josm.gui.dialogs.relation.WayConnectionType.Direction;
014    import org.openstreetmap.josm.tools.ImageProvider;
015    
016    public class MemberTableLinkedCellRenderer extends MemberTableCellRenderer {
017    
018        final static Image arrowUp = ImageProvider.get("dialogs/relation", "arrowup").getImage();
019        final static Image arrowDown = ImageProvider.get("dialogs/relation", "arrowdown").getImage();
020        final static Image corners = ImageProvider.get("dialogs/relation", "roundedcorners").getImage();
021        final static Image roundabout_right = ImageProvider.get("dialogs/relation", "roundabout_right_tiny").getImage();
022        final static Image roundabout_left = ImageProvider.get("dialogs/relation", "roundabout_left_tiny").getImage();
023        private WayConnectionType value = new WayConnectionType();
024    
025        @Override
026        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
027                int row, int column) {
028    
029            reset();
030            if (value == null)
031                return this;
032    
033            this.value = (WayConnectionType) value;
034            renderForeground(isSelected);
035            //setText(value.toString());
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                }
082                else {
083                    g.setColor(Color.red);
084                    if(value.isOnewayHead) {
085                        g.drawRect(xoff-1, p - 3 - w, w, w);
086                    } else {
087                        g.drawRect(xoff-1 + xowloop, p - 1 - w, w, w);
088                    }
089                    y1 = p;
090                }
091            }
092    
093            if (value.linkNext) {
094                g.setColor(Color.black);
095                if(value.isOnewayTail) {
096                    g.fillRect(xoff - 1, ymax, 3, 1);
097                } else {
098                    g.fillRect(xoff - 1 + xowloop, ymax, 3, 1);
099                }
100                y2 = ymax;
101            } else {
102                if (value.isLoop) {
103                    g.setColor(Color.black);
104                    y2 = ymax - 5;
105                    g.fillRect(xoff-1, y2+2, 3, 3);
106                    g.drawLine(xoff, y2, xoff, y2+2);
107                    g.drawImage(corners,xoff+xloop-2,y2+1,xoff+xloop+1,y2+4, 2,2,5,5, new Color(0,0,0,0), null);
108                    g.drawLine(xoff+3-1,y2+3,xoff+xloop-3,y2+3);
109                }
110                else {
111                    g.setColor(Color.red);
112                    if(value.isOnewayTail) {
113                        g.drawRect(xoff-1, ymax - p + 3, w, w);
114                    } else {
115                        g.drawRect(xoff-1 + xowloop, ymax - p + 1, w, w);
116                    }
117                    y2 = ymax - p;
118                }
119            }
120    
121            /* vertical lines */
122            g.setColor(Color.black);
123            if (value.isLoop) {
124                g.drawLine(xoff+xloop, y1, xoff+xloop, y2);
125            }
126    
127            if (value.isOnewayHead) {
128                setDotted(g);
129                y1 = 7;
130    
131                int xValues [] = {xoff - xowloop + 1, xoff - xowloop + 1, xoff};
132                int yValues [] = {ymax, y1+1, 1};
133                g.drawPolyline(xValues, yValues, 3);
134                unsetDotted(g);
135                g.drawLine(xoff + xowloop, y1+1, xoff, 1);
136            }
137    
138            if(value.isOnewayTail){
139                setDotted(g);
140                y2 = ymax - 7;
141    
142                int xValues [] = {xoff+1, xoff - xowloop + 1, xoff - xowloop + 1};
143                int yValues [] = {ymax-1, y2, y1};
144                g.drawPolyline(xValues, yValues, 3);
145                unsetDotted(g);
146                g.drawLine(xoff + xowloop, y2, xoff, ymax-1);
147            }
148    
149            if ((value.isOnewayLoopForwardPart || value.isOnewayLoopBackwardPart) && !value.isOnewayTail && !value.isOnewayHead) {
150                setDotted(g);
151                g.drawLine(xoff - xowloop+1, y1, xoff - xowloop+1, y2 + 1);
152                unsetDotted(g);
153            }
154    
155            if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart){
156                g.drawLine(xoff, y1, xoff, y2);
157            }
158    
159            g.drawLine(xoff+xowloop, y1, xoff+xowloop, y2);
160    
161            /* special icons */
162            Image arrow = null;
163            switch (value.direction) {
164            case FORWARD:
165                arrow = arrowDown;
166                break;
167            case BACKWARD:
168                arrow = arrowUp;
169                break;
170            }
171            if (value.direction == Direction.ROUNDABOUT_LEFT) {
172                g.drawImage(roundabout_left, xoff-6, 1, null);
173            } else if (value.direction == Direction.ROUNDABOUT_RIGHT) {
174                g.drawImage(roundabout_right, xoff-6, 1, null);
175            }
176    
177            if (!value.isOnewayLoopForwardPart && !value.isOnewayLoopBackwardPart &&
178                    (arrow != null)) {
179                g.drawImage(arrow, xoff-3, (y1 + y2) / 2 - 2, null);
180            }
181    
182            if (value.isOnewayLoopBackwardPart && value.isOnewayLoopForwardPart) {
183                if(arrow == arrowDown) {
184                    arrow = arrowUp;
185                } else if (arrow == arrowUp) {
186                    arrow = arrowDown;
187                }
188            }
189    
190            if ((arrow != null)) {
191                g.drawImage(arrow, xoff+xowloop-3, (y1 + y2) / 2 - 2, null);
192            }
193        }
194    
195        private void setDotted(Graphics g) {
196            ((Graphics2D)g).setStroke(new BasicStroke(
197                    1f,
198                    BasicStroke.CAP_BUTT,
199                    BasicStroke.CAP_BUTT,
200                    5f,
201                    new float[] {1f, 2f},
202                    0f));
203        }
204    
205        private void unsetDotted(Graphics g) {
206            ((Graphics2D)g).setStroke(new BasicStroke());
207        }
208    }