Changeset 23207 in osm


Ignore:
Timestamp:
2010-09-16T11:32:35+02:00 (14 years ago)
Author:
stoecker
Message:

rework preferences and layer storage

Location:
applications/editors/josm/plugins/wmsplugin
Files:
1 added
16 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/wmsplugin/build.xml

    r22856 r23207  
    2929
    3030        <property name="commit.message" value="fixed josm bug 4671 - wms url for sicily has changed" />
    31         <property name="plugin.main.version" value="3451" />
    32 
     31        <property name="plugin.main.version" value="3530" />
    3332
    3433        <property name="josm" location="../../core/dist/josm-custom.jar" />
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/GeorefImage.java

    r22929 r23207  
    2121
    2222public class GeorefImage implements Serializable {
    23         private static final long serialVersionUID = 1L;
    24 
    25         public enum State { IMAGE, NOT_IN_CACHE, FAILED};
    26 
    27         private WMSLayer layer;
    28         private State state;
    29 
    30         private BufferedImage image;
    31         private SoftReference<BufferedImage> reImg;
    32         private int xIndex;
    33         private int yIndex;
    34 
    35 
    36         public EastNorth getMin() {
    37                 return layer.getEastNorth(xIndex, yIndex);
    38         }
    39 
    40         public EastNorth getMax() {
    41                 return layer.getEastNorth(xIndex+1, yIndex+1);
    42         }
    43 
    44 
    45         public GeorefImage(WMSLayer layer) {
    46                 this.layer = layer;
    47         }
    48 
    49         public void changePosition(int xIndex, int yIndex) {
    50                 if (!equalPosition(xIndex, yIndex)) {
    51                         this.xIndex = xIndex;
    52                         this.yIndex = yIndex;
    53                         this.image = null;
    54                         flushedResizedCachedInstance();
    55                 }
    56         }
    57 
    58         public boolean equalPosition(int xIndex, int yIndex) {
    59                 return this.xIndex == xIndex && this.yIndex == yIndex;
    60         }
    61 
    62         public void changeImage(State state, BufferedImage image) {
    63                 flushedResizedCachedInstance();
    64                 this.image = image;
    65                 this.state = state;
    66 
    67                 switch (state) {
    68                 case FAILED:
    69                 {
    70                         BufferedImage img = createImage();
    71                         Graphics g = img.getGraphics();
    72                         g.setColor(Color.RED);
    73                         g.fillRect(0, 0, img.getWidth(), img.getHeight());
    74                         g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
    75                         g.setColor(Color.BLACK);
    76                         g.drawString(tr("Exception occurred"), 10, img.getHeight()/2);
    77                         this.image = img;
    78                         break;
    79                 }
    80                 case NOT_IN_CACHE:
    81                 {
    82                         BufferedImage img = createImage();
    83                         Graphics g = img.getGraphics();
    84                         g.setColor(Color.GRAY);
    85                         g.fillRect(0, 0, img.getWidth(), img.getHeight());
    86                         Font font = g.getFont();
    87                         Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
    88                         g.setFont(tempFont);
    89                         g.setColor(Color.BLACK);
    90                         g.drawString(tr("Not in cache"), 10, img.getHeight()/2);
    91                         g.setFont(font);
    92                         this.image = img;
    93                         break;
    94                 }
    95                 default:
    96                         break;
    97                 }
    98         }
    99 
    100         private BufferedImage createImage() {
    101                 return new BufferedImage(layer.getBaseImageWidth(), layer.getBaseImageHeight(), BufferedImage.TYPE_INT_RGB);
    102         }
    103 
    104         public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) {
    105                 if (image == null)
    106                         return false;
    107 
    108                 if(!(this.xIndex == xIndex && this.yIndex == yIndex)){
    109                         return false;
    110                 }
    111 
    112                 int left = layer.getImageX(xIndex);
    113                 int bottom = layer.getImageY(yIndex);
    114                 int width = layer.getImageWidth(xIndex);
    115                 int height = layer.getImageHeight(yIndex);
    116 
    117                 int x = left - leftEdge;
    118                 int y = nc.getHeight() - (bottom - bottomEdge) - height;
    119 
    120                 // This happens if you zoom outside the world
    121                 if(width == 0 || height == 0)
    122                         return false;
    123 
    124                 BufferedImage img = reImg == null?null:reImg.get();
    125                 if(img != null && img.getWidth() == width && img.getHeight() == height) {
    126                         g.drawImage(img, x, y, null);
    127                         return true;
    128                 }
    129 
    130                 boolean alphaChannel = WMSLayer.PROP_ALPHA_CHANNEL.get() && getImage().getTransparency() != Transparency.OPAQUE;
    131 
    132                 try {
    133                         if(img != null) img.flush();
    134                         long freeMem = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
    135                         //System.out.println("Free Memory:           "+ (freeMem/1024/1024) +" MB");
    136                         // Notice that this value can get negative due to integer overflows
    137                         //System.out.println("Img Size:              "+ (width*height*3/1024/1024) +" MB");
    138 
    139                         int multipl = alphaChannel ? 4 : 3;
    140                         // This happens when requesting images while zoomed out and then zooming in
    141                         // Storing images this large in memory will certainly hang up JOSM. Luckily
    142                         // traditional rendering is as fast at these zoom levels, so it's no loss.
    143                         // Also prevent caching if we're out of memory soon
    144                         if(width > 2000 || height > 2000 || width*height*multipl > freeMem) {
    145                                 fallbackDraw(g, getImage(), x, y, width, height);
    146                         } else {
    147                                 // We haven't got a saved resized copy, so resize and cache it
    148                                 img = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
    149                                 img.getGraphics().drawImage(getImage(),
    150                                                 0, 0, width, height, // dest
    151                                                 0, 0, getImage().getWidth(null), getImage().getHeight(null), // src
    152                                                 null);
    153                                 img.getGraphics().dispose();
    154                                 g.drawImage(img, x, y, null);
    155                                 reImg = new SoftReference<BufferedImage>(img);
    156                         }
    157                 } catch(Exception e) {
    158                         fallbackDraw(g, getImage(), x, y, width, height);
    159                 }
    160                 return true;
    161         }
    162 
    163         private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height) {
    164                 flushedResizedCachedInstance();
    165                 g.drawImage(
    166                                 img, x, y, x + width, y + height,
    167                                 0, 0, img.getWidth(null), img.getHeight(null),
    168                                 null);
    169         }
    170 
    171         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    172                 state = (State) in.readObject();
    173                 boolean hasImage = in.readBoolean();
    174                 if (hasImage)
    175                         image = (ImageIO.read(ImageIO.createImageInputStream(in)));
    176                 else {
    177                         in.readObject(); // read null from input stream
    178                         image = null;
    179                 }
    180         }
    181 
    182         private void writeObject(ObjectOutputStream out) throws IOException {
    183                 out.writeObject(state);
    184                 if(getImage() == null) {
    185                         out.writeBoolean(false);
    186                         out.writeObject(null);
    187                 } else {
    188                         out.writeBoolean(true);
    189                         ImageIO.write(getImage(), "png", ImageIO.createImageOutputStream(out));
    190                 }
    191         }
    192 
    193         public void flushedResizedCachedInstance() {
    194                 if (reImg != null) {
    195                         BufferedImage img = reImg.get();
    196                         if (img != null) {
    197                                 img.flush();
    198                         }
    199                 }
    200                 reImg = null;
    201         }
    202 
    203 
    204         public BufferedImage getImage() {
    205                 return image;
    206         }
    207 
    208         public State getState() {
    209                 return state;
    210         }
    211 
    212         public int getXIndex() {
    213                 return xIndex;
    214         }
    215 
    216         public int getYIndex() {
    217                 return yIndex;
    218         }
    219 
    220         public void setLayer(WMSLayer layer) {
    221                 this.layer = layer;
    222         }
     23    private static final long serialVersionUID = 1L;
     24
     25    public enum State { IMAGE, NOT_IN_CACHE, FAILED};
     26
     27    private WMSLayer layer;
     28    private State state;
     29
     30    private BufferedImage image;
     31    private SoftReference<BufferedImage> reImg;
     32    private int xIndex;
     33    private int yIndex;
     34
     35
     36    public EastNorth getMin() {
     37        return layer.getEastNorth(xIndex, yIndex);
     38    }
     39
     40    public EastNorth getMax() {
     41        return layer.getEastNorth(xIndex+1, yIndex+1);
     42    }
     43
     44
     45    public GeorefImage(WMSLayer layer) {
     46        this.layer = layer;
     47    }
     48
     49    public void changePosition(int xIndex, int yIndex) {
     50        if (!equalPosition(xIndex, yIndex)) {
     51            this.xIndex = xIndex;
     52            this.yIndex = yIndex;
     53            this.image = null;
     54            flushedResizedCachedInstance();
     55        }
     56    }
     57
     58    public boolean equalPosition(int xIndex, int yIndex) {
     59        return this.xIndex == xIndex && this.yIndex == yIndex;
     60    }
     61
     62    public void changeImage(State state, BufferedImage image) {
     63        flushedResizedCachedInstance();
     64        this.image = image;
     65        this.state = state;
     66
     67        switch (state) {
     68        case FAILED:
     69        {
     70            BufferedImage img = createImage();
     71            Graphics g = img.getGraphics();
     72            g.setColor(Color.RED);
     73            g.fillRect(0, 0, img.getWidth(), img.getHeight());
     74            g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
     75            g.setColor(Color.BLACK);
     76            g.drawString(tr("Exception occurred"), 10, img.getHeight()/2);
     77            this.image = img;
     78            break;
     79        }
     80        case NOT_IN_CACHE:
     81        {
     82            BufferedImage img = createImage();
     83            Graphics g = img.getGraphics();
     84            g.setColor(Color.GRAY);
     85            g.fillRect(0, 0, img.getWidth(), img.getHeight());
     86            Font font = g.getFont();
     87            Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
     88            g.setFont(tempFont);
     89            g.setColor(Color.BLACK);
     90            g.drawString(tr("Not in cache"), 10, img.getHeight()/2);
     91            g.setFont(font);
     92            this.image = img;
     93            break;
     94        }
     95        default:
     96            break;
     97        }
     98    }
     99
     100    private BufferedImage createImage() {
     101        return new BufferedImage(layer.getBaseImageWidth(), layer.getBaseImageHeight(), BufferedImage.TYPE_INT_RGB);
     102    }
     103
     104    public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) {
     105        if (image == null)
     106            return false;
     107
     108        if(!(this.xIndex == xIndex && this.yIndex == yIndex)){
     109            return false;
     110        }
     111
     112        int left = layer.getImageX(xIndex);
     113        int bottom = layer.getImageY(yIndex);
     114        int width = layer.getImageWidth(xIndex);
     115        int height = layer.getImageHeight(yIndex);
     116
     117        int x = left - leftEdge;
     118        int y = nc.getHeight() - (bottom - bottomEdge) - height;
     119
     120        // This happens if you zoom outside the world
     121        if(width == 0 || height == 0)
     122            return false;
     123
     124        BufferedImage img = reImg == null?null:reImg.get();
     125        if(img != null && img.getWidth() == width && img.getHeight() == height) {
     126            g.drawImage(img, x, y, null);
     127            return true;
     128        }
     129
     130        boolean alphaChannel = WMSLayer.PROP_ALPHA_CHANNEL.get() && getImage().getTransparency() != Transparency.OPAQUE;
     131
     132        try {
     133            if(img != null) img.flush();
     134            long freeMem = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
     135            //System.out.println("Free Memory:           "+ (freeMem/1024/1024) +" MB");
     136            // Notice that this value can get negative due to integer overflows
     137            //System.out.println("Img Size:              "+ (width*height*3/1024/1024) +" MB");
     138
     139            int multipl = alphaChannel ? 4 : 3;
     140            // This happens when requesting images while zoomed out and then zooming in
     141            // Storing images this large in memory will certainly hang up JOSM. Luckily
     142            // traditional rendering is as fast at these zoom levels, so it's no loss.
     143            // Also prevent caching if we're out of memory soon
     144            if(width > 2000 || height > 2000 || width*height*multipl > freeMem) {
     145                fallbackDraw(g, getImage(), x, y, width, height);
     146            } else {
     147                // We haven't got a saved resized copy, so resize and cache it
     148                img = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
     149                img.getGraphics().drawImage(getImage(),
     150                        0, 0, width, height, // dest
     151                        0, 0, getImage().getWidth(null), getImage().getHeight(null), // src
     152                        null);
     153                img.getGraphics().dispose();
     154                g.drawImage(img, x, y, null);
     155                reImg = new SoftReference<BufferedImage>(img);
     156            }
     157        } catch(Exception e) {
     158            fallbackDraw(g, getImage(), x, y, width, height);
     159        }
     160        return true;
     161    }
     162
     163    private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height) {
     164        flushedResizedCachedInstance();
     165        g.drawImage(
     166                img, x, y, x + width, y + height,
     167                0, 0, img.getWidth(null), img.getHeight(null),
     168                null);
     169    }
     170
     171    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
     172        state = (State) in.readObject();
     173        boolean hasImage = in.readBoolean();
     174        if (hasImage)
     175            image = (ImageIO.read(ImageIO.createImageInputStream(in)));
     176        else {
     177            in.readObject(); // read null from input stream
     178            image = null;
     179        }
     180    }
     181
     182    private void writeObject(ObjectOutputStream out) throws IOException {
     183        out.writeObject(state);
     184        if(getImage() == null) {
     185            out.writeBoolean(false);
     186            out.writeObject(null);
     187        } else {
     188            out.writeBoolean(true);
     189            ImageIO.write(getImage(), "png", ImageIO.createImageOutputStream(out));
     190        }
     191    }
     192
     193    public void flushedResizedCachedInstance() {
     194        if (reImg != null) {
     195            BufferedImage img = reImg.get();
     196            if (img != null) {
     197                img.flush();
     198            }
     199        }
     200        reImg = null;
     201    }
     202
     203
     204    public BufferedImage getImage() {
     205        return image;
     206    }
     207
     208    public State getState() {
     209        return state;
     210    }
     211
     212    public int getXIndex() {
     213        return xIndex;
     214    }
     215
     216    public int getYIndex() {
     217        return yIndex;
     218    }
     219
     220    public void setLayer(WMSLayer layer) {
     221        this.layer = layer;
     222    }
    223223}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/Grabber.java

    r22929 r23207  
    1111
    1212abstract public class Grabber implements Runnable {
    13         protected final MapView mv;
    14         protected final WMSLayer layer;
    15         protected final CacheFiles cache;
     13    protected final MapView mv;
     14    protected final WMSLayer layer;
     15    protected final CacheFiles cache;
    1616
    17         protected ProjectionBounds b;
    18         protected Projection proj;
    19         protected double pixelPerDegree;
    20         protected WMSRequest request;
    21         protected volatile boolean canceled;
     17    protected ProjectionBounds b;
     18    protected Projection proj;
     19    protected double pixelPerDegree;
     20    protected WMSRequest request;
     21    protected volatile boolean canceled;
    2222
    23         Grabber(MapView mv, WMSLayer layer, CacheFiles cache) {
    24                 this.mv = mv;
    25                 this.layer = layer;
    26                 this.cache = cache;
    27         }
     23    Grabber(MapView mv, WMSLayer layer, CacheFiles cache) {
     24        this.mv = mv;
     25        this.layer = layer;
     26        this.cache = cache;
     27    }
    2828
    29         private void updateState(WMSRequest request) {
    30                 b = new ProjectionBounds(
    31                                 layer.getEastNorth(request.getXIndex(), request.getYIndex()),
    32                                 layer.getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1));
    33                 if (b.min != null && b.max != null && WMSPlugin.PROP_OVERLAP.get()) {
    34                         double eastSize =  b.max.east() - b.min.east();
    35                         double northSize =  b.max.north() - b.min.north();
     29    private void updateState(WMSRequest request) {
     30        b = new ProjectionBounds(
     31                layer.getEastNorth(request.getXIndex(), request.getYIndex()),
     32                layer.getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1));
     33        if (b.min != null && b.max != null && WMSPlugin.instance.PROP_OVERLAP.get()) {
     34            double eastSize =  b.max.east() - b.min.east();
     35            double northSize =  b.max.north() - b.min.north();
    3636
    37                         double eastCoef = WMSPlugin.PROP_OVERLAP_EAST.get() / 100.0;
    38                         double northCoef = WMSPlugin.PROP_OVERLAP_NORTH.get() / 100.0;
     37            double eastCoef = WMSPlugin.instance.PROP_OVERLAP_EAST.get() / 100.0;
     38            double northCoef = WMSPlugin.instance.PROP_OVERLAP_NORTH.get() / 100.0;
    3939
    40                         this.b = new ProjectionBounds( new EastNorth(b.min.east(),
    41                                         b.min.north()),
    42                                         new EastNorth(b.max.east() + eastCoef * eastSize,
    43                                                         b.max.north() + northCoef * northSize));
    44                 }
     40            this.b = new ProjectionBounds( new EastNorth(b.min.east(),
     41                    b.min.north()),
     42                    new EastNorth(b.max.east() + eastCoef * eastSize,
     43                            b.max.north() + northCoef * northSize));
     44        }
    4545
    46                 this.proj = Main.proj;
    47                 this.pixelPerDegree = request.getPixelPerDegree();
    48                 this.request = request;
    49         }
     46        this.proj = Main.proj;
     47        this.pixelPerDegree = request.getPixelPerDegree();
     48        this.request = request;
     49    }
    5050
    51         abstract void fetch(WMSRequest request) throws Exception; // the image fetch code
     51    abstract void fetch(WMSRequest request) throws Exception; // the image fetch code
    5252
    53         int width(){
    54                 return layer.getBaseImageWidth();
    55         }
    56         int height(){
    57                 return layer.getBaseImageHeight();
    58         }
     53    int width(){
     54        return layer.getBaseImageWidth();
     55    }
     56    int height(){
     57        return layer.getBaseImageHeight();
     58    }
    5959
    60         @Override
    61         public void run() {
    62                 while (true) {
    63                         if (canceled) {
    64                                 return;
    65                         }
    66                         WMSRequest request = layer.getRequest();
    67                         if (request == null) {
    68                                 return;
    69                         }
    70                         updateState(request);
    71                         if(!loadFromCache(request)){
    72                                 attempt(request);
    73                         }
    74                         if (request.getState() != null) {
    75                                 layer.finishRequest(request);
    76                                 mv.repaint();
    77                         }
    78                 }
    79         }
     60    @Override
     61    public void run() {
     62        while (true) {
     63            if (canceled) {
     64                return;
     65            }
     66            WMSRequest request = layer.getRequest();
     67            if (request == null) {
     68                return;
     69            }
     70            updateState(request);
     71            if(!loadFromCache(request)){
     72                attempt(request);
     73            }
     74            if (request.getState() != null) {
     75                layer.finishRequest(request);
     76                mv.repaint();
     77            }
     78        }
     79    }
    8080
    81         protected void attempt(WMSRequest request){ // try to fetch the image
    82                 int maxTries = 5; // n tries for every image
    83                 for (int i = 1; i <= maxTries; i++) {
    84                         if (canceled) {
    85                                 return;
    86                         }
    87                         try {
    88                                 if (!layer.requestIsValid(request)) {
    89                                         return;
    90                                 }
    91                                 fetch(request);
    92                                 break; // break out of the retry loop
    93                         } catch (Exception e) {
    94                                 try { // sleep some time and then ask the server again
    95                                         Thread.sleep(random(1000, 2000));
    96                                 } catch (InterruptedException e1) {}
     81    protected void attempt(WMSRequest request){ // try to fetch the image
     82        int maxTries = 5; // n tries for every image
     83        for (int i = 1; i <= maxTries; i++) {
     84            if (canceled) {
     85                return;
     86            }
     87            try {
     88                if (!layer.requestIsValid(request)) {
     89                    return;
     90                }
     91                fetch(request);
     92                break; // break out of the retry loop
     93            } catch (Exception e) {
     94                try { // sleep some time and then ask the server again
     95                    Thread.sleep(random(1000, 2000));
     96                } catch (InterruptedException e1) {}
    9797
    98                                 if(i == maxTries) {
    99                                         e.printStackTrace();
    100                                         request.finish(State.FAILED, null);
    101                                 }
    102                         }
    103                 }
    104         }
     98                if(i == maxTries) {
     99                    e.printStackTrace();
     100                    request.finish(State.FAILED, null);
     101                }
     102            }
     103        }
     104    }
    105105
    106         public static int random(int min, int max) {
    107                 return (int)(Math.random() * ((max+1)-min) ) + min;
    108         }
     106    public static int random(int min, int max) {
     107        return (int)(Math.random() * ((max+1)-min) ) + min;
     108    }
    109109
    110         abstract public boolean loadFromCache(WMSRequest request);
     110    abstract public boolean loadFromCache(WMSRequest request);
    111111
    112         public void cancel() {
    113                 canceled = true;
    114         }
     112    public void cancel() {
     113        canceled = true;
     114    }
    115115}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/HTMLGrabber.java

    r22712 r23207  
    1515
    1616public class HTMLGrabber extends WMSGrabber {
    17         HTMLGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
    18                 super(mv, layer, cache);
    19                 this.baseURL = layer.baseURL.replaceFirst("html:", "");
    20         }
     17    HTMLGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
     18        super(mv, layer, cache);
     19    }
    2120
    22         @Override
    23         protected BufferedImage grab(URL url) throws IOException {
    24                 String urlstring = url.toExternalForm();
     21    @Override
     22    protected BufferedImage grab(URL url) throws IOException {
     23        String urlstring = url.toExternalForm();
    2524
    26                 System.out.println("Grabbing HTML " + url);
     25        System.out.println("Grabbing HTML " + url);
    2726
    28                 ArrayList<String> cmdParams = new ArrayList<String>();
    29                 StringTokenizer st = new StringTokenizer(MessageFormat.format(
    30                                 Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
    31                 while( st.hasMoreTokens() )
    32                         cmdParams.add(st.nextToken());
     27        ArrayList<String> cmdParams = new ArrayList<String>();
     28        StringTokenizer st = new StringTokenizer(MessageFormat.format(
     29                Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
     30        while( st.hasMoreTokens() )
     31            cmdParams.add(st.nextToken());
    3332
    34                 ProcessBuilder builder = new ProcessBuilder( cmdParams);
     33        ProcessBuilder builder = new ProcessBuilder( cmdParams);
    3534
    36                 Process browser;
    37                 try {
    38                         browser = builder.start();
    39                 } catch(IOException ioe) {
    40                         throw new IOException( "Could not start browser. Please check that the executable path is correct.\n" + ioe.getMessage() );
    41                 }
     35        Process browser;
     36        try {
     37            browser = builder.start();
     38        } catch(IOException ioe) {
     39            throw new IOException( "Could not start browser. Please check that the executable path is correct.\n" + ioe.getMessage() );
     40        }
    4241
    43                 BufferedImage img = ImageIO.read(browser.getInputStream());
    44                 cache.saveImg(urlstring, img);
    45                 return img;
    46         }
     42        BufferedImage img = ImageIO.read(browser.getInputStream());
     43        cache.saveImg(urlstring, img);
     44        return img;
     45    }
    4746}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java

    r22677 r23207  
    2929
    3030public class Map_Rectifier_WMSmenuAction extends JosmAction {
    31         /**
    32          * Class that bundles all required information of a rectifier service
    33          */
    34         public static class RectifierService {
    35                 private final String name;
    36                 private final String url;
    37                 private final String wmsUrl;
    38                 private final Pattern urlRegEx;
    39                 private final Pattern idValidator;
    40                 public JRadioButton btn;
    41                 /**
    42                  * @param name: Name of the rectifing service
    43                  * @param url: URL to the service where users can register, upload, etc.
    44                  * @param wmsUrl: URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
    45                  * @param urlRegEx: a regular expression that determines if a given URL is one of the service and returns the WMS id if so
    46                  * @param idValidator: regular expression that checks if a given ID is syntactically valid
    47                  */
    48                 public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
    49                         this.name = name;
    50                         this.url = url;
    51                         this.wmsUrl = wmsUrl;
    52                         this.urlRegEx = Pattern.compile(urlRegEx);
    53                         this.idValidator = Pattern.compile(idValidator);
    54                 }
    55 
    56                 public boolean isSelected() {
    57                         return btn.isSelected();
    58                 }
    59         }
    60 
    61         /**
    62          * List of available rectifier services. May be extended from the outside
    63          */
    64         public ArrayList<RectifierService> services = new ArrayList<RectifierService>();
    65 
    66         public Map_Rectifier_WMSmenuAction() {
    67                 super(tr("Rectified Image..."),
    68                                 "OLmarker",
    69                                 tr("Download Rectified Images From Various Services"),
    70                                 Shortcut.registerShortcut("wms:rectimg",
    71                                                 tr("WMS: {0}", tr("Rectified Image...")),
    72                                                 KeyEvent.VK_R,
    73                                                 Shortcut.GROUP_NONE),
    74                                                 true
    75                 );
    76 
    77                 // Add default services
    78                 services.add(
    79                                 new RectifierService("Metacarta Map Rectifier",
    80                                                 "http://labs.metacarta.com/rectifier/",
    81                                                 "http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
    82                                                 + "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
    83                                                 // This matches more than the "classic" WMS link, so users can pretty much
    84                                                 // copy any link as long as it includes the ID
    85                                                 "labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
    86                                 "^[0-9]+$")
    87                 );
    88                 services.add(
    89                                 // TODO: Change all links to mapwarper.net once the project has moved.
    90                                 // The RegEx already matches the new URL and old URLs will be forwarded
    91                                 // to make the transition as smooth as possible for the users
    92                                 new RectifierService("Geothings Map Warper",
    93                                                 "http://warper.geothings.net/",
    94                                                 "http://warper.geothings.net/maps/wms/__s__?request=GetMap&version=1.1.1"
    95                                                 + "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
    96                                                 // This matches more than the "classic" WMS link, so users can pretty much
    97                                                 // copy any link as long as it includes the ID
    98                                                 "(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
    99                                 "^[0-9]+$")
    100                 );
    101 
    102                 // This service serves the purpose of "just this once" without forcing the user
    103                 // to commit the link to the preferences
    104 
    105                 // Clipboard content gets trimmed, so matching whitespace only ensures that this
    106                 // service will never be selected automatically.
    107                 services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
    108         }
    109 
    110         public void actionPerformed(ActionEvent e) {
    111                 JPanel panel = new JPanel(new GridBagLayout());
    112                 panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
    113 
    114                 JTextField tfWmsUrl = new JTextField(30);
    115 
    116                 String clip = getClipboardContents();
    117                 ButtonGroup group = new ButtonGroup();
    118 
    119                 JRadioButton firstBtn = null;
    120                 for(RectifierService s : services) {
    121                         JRadioButton serviceBtn = new JRadioButton(s.name);
    122                         if(firstBtn == null)
    123                                 firstBtn = serviceBtn;
    124                         // Checks clipboard contents against current service if no match has been found yet.
    125                         // If the contents match, they will be inserted into the text field and the corresponding
    126                         // service will be pre-selected.
    127                         if(!clip.equals("") && tfWmsUrl.getText().equals("")
    128                                         && (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
    129                                 serviceBtn.setSelected(true);
    130                                 tfWmsUrl.setText(clip);
    131                         }
    132                         s.btn = serviceBtn;
    133                         group.add(serviceBtn);
    134                         if(!s.url.equals("")) {
    135                                 panel.add(serviceBtn, GBC.std());
    136                                 panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
    137                         } else
    138                                 panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
    139                 }
    140 
    141                 // Fallback in case no match was found
    142                 if(tfWmsUrl.getText().equals("") && firstBtn != null)
    143                         firstBtn.setSelected(true);
    144 
    145                 panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
    146                 panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    147 
    148                 ExtendedDialog diag = new ExtendedDialog(Main.parent,
    149                                 tr("Add Rectified Image"),
    150 
    151                                 new String[] {tr("Add Rectified Image"), tr("Cancel")});
    152                 diag.setContent(panel);
    153                 diag.setButtonIcons(new String[] {"OLmarker.png", "cancel.png"});
    154 
    155                 // This repeatedly shows the dialog in case there has been an error.
    156                 // The loop is break;-ed if the users cancels
    157                 outer: while(true) {
    158                         diag.showDialog();
    159                         int answer = diag.getValue();
    160                         // Break loop when the user cancels
    161                         if(answer != 1)
    162                                 break;
    163 
    164                         String text = tfWmsUrl.getText().trim();
    165                         // Loop all services until we find the selected one
    166                         for(RectifierService s : services) {
    167                                 if(!s.isSelected())
    168                                         continue;
    169 
    170                                 // We've reached the custom WMS URL service
    171                                 // Just set the URL and hope everything works out
    172                                 if(s.wmsUrl.equals("")) {
    173                                         addWMSLayer(s.name + " (" + text + ")", text);
    174                                         break outer;
    175                                 }
    176 
    177                                 // First try to match if the entered string as an URL
    178                                 Matcher m = s.urlRegEx.matcher(text);
    179                                 if(m.find()) {
    180                                         String id = m.group(1);
    181                                         String newURL = s.wmsUrl.replaceAll("__s__", id);
    182                                         String title = s.name + " (" + id + ")";
    183                                         addWMSLayer(title, newURL);
    184                                         break outer;
    185                                 }
    186                                 // If not, look if it's a valid ID for the selected service
    187                                 if(s.idValidator.matcher(text).matches()) {
    188                                         String newURL = s.wmsUrl.replaceAll("__s__", text);
    189                                         String title = s.name + " (" + text + ")";
    190                                         addWMSLayer(title, newURL);
    191                                         break outer;
    192                                 }
    193 
    194                                 // We've found the selected service, but the entered string isn't suitable for
    195                                 // it. So quit checking the other radio buttons
    196                                 break;
    197                         }
    198 
    199                         // and display an error message. The while(true) ensures that the dialog pops up again
    200                         JOptionPane.showMessageDialog(Main.parent,
    201                                         tr("Couldn't match the entered link or id to the selected service. Please try again."),
    202                                         tr("No valid WMS URL or id"),
    203                                         JOptionPane.ERROR_MESSAGE);
    204                         diag.setVisible(true);
    205                 }
    206         }
    207 
    208         /**
    209          * Adds a WMS Layer with given title and URL
    210          * @param title: Name of the layer as it will shop up in the layer manager
    211          * @param url: URL to the WMS server
    212          * @param cookies: Cookies to send with each image request (Format: josm=is; very=cool)
    213          */
    214         private void addWMSLayer(String title, String url, String cookies) {
    215                 WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
    216                 Main.main.addLayer(wmsLayer);
    217         }
    218 
    219         /**
    220          * Adds a WMS Layer with given title and URL
    221          * @param title: Name of the layer as it will shop up in the layer manager
    222          * @param url: URL to the WMS server
    223          */
    224         private void addWMSLayer(String title, String url) {
    225                 addWMSLayer(title, url, "");
    226         }
    227 
    228         /**
    229          * Helper function that extracts a String from the Clipboard if available.
    230          * Returns an empty String otherwise
    231          * @return String Clipboard contents if available
    232          */
    233         private String getClipboardContents() {
    234                 String result = "";
    235                 Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
    236 
    237                 if(contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor))
    238                         return "";
    239 
    240                 try {
    241                         result = (String)contents.getTransferData(DataFlavor.stringFlavor);
    242                 } catch(Exception ex) {
    243                         return "";
    244                 }
    245                 return result.trim();
    246         }
     31    /**
     32     * Class that bundles all required information of a rectifier service
     33     */
     34    public static class RectifierService {
     35        private final String name;
     36        private final String url;
     37        private final String wmsUrl;
     38        private final Pattern urlRegEx;
     39        private final Pattern idValidator;
     40        public JRadioButton btn;
     41        /**
     42         * @param name: Name of the rectifing service
     43         * @param url: URL to the service where users can register, upload, etc.
     44         * @param wmsUrl: URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
     45         * @param urlRegEx: a regular expression that determines if a given URL is one of the service and returns the WMS id if so
     46         * @param idValidator: regular expression that checks if a given ID is syntactically valid
     47         */
     48        public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
     49            this.name = name;
     50            this.url = url;
     51            this.wmsUrl = wmsUrl;
     52            this.urlRegEx = Pattern.compile(urlRegEx);
     53            this.idValidator = Pattern.compile(idValidator);
     54        }
     55
     56        public boolean isSelected() {
     57            return btn.isSelected();
     58        }
     59    }
     60
     61    /**
     62     * List of available rectifier services. May be extended from the outside
     63     */
     64    public ArrayList<RectifierService> services = new ArrayList<RectifierService>();
     65
     66    public Map_Rectifier_WMSmenuAction() {
     67        super(tr("Rectified Image..."),
     68                "OLmarker",
     69                tr("Download Rectified Images From Various Services"),
     70                Shortcut.registerShortcut("wms:rectimg",
     71                        tr("WMS: {0}", tr("Rectified Image...")),
     72                        KeyEvent.VK_R,
     73                        Shortcut.GROUP_NONE),
     74                        true
     75        );
     76
     77        // Add default services
     78        services.add(
     79                new RectifierService("Metacarta Map Rectifier",
     80                        "http://labs.metacarta.com/rectifier/",
     81                        "http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
     82                        + "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
     83                        // This matches more than the "classic" WMS link, so users can pretty much
     84                        // copy any link as long as it includes the ID
     85                        "labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
     86                "^[0-9]+$")
     87        );
     88        services.add(
     89                // TODO: Change all links to mapwarper.net once the project has moved.
     90                // The RegEx already matches the new URL and old URLs will be forwarded
     91                // to make the transition as smooth as possible for the users
     92                new RectifierService("Geothings Map Warper",
     93                        "http://warper.geothings.net/",
     94                        "http://warper.geothings.net/maps/wms/__s__?request=GetMap&version=1.1.1"
     95                        + "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
     96                        // This matches more than the "classic" WMS link, so users can pretty much
     97                        // copy any link as long as it includes the ID
     98                        "(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
     99                "^[0-9]+$")
     100        );
     101
     102        // This service serves the purpose of "just this once" without forcing the user
     103        // to commit the link to the preferences
     104
     105        // Clipboard content gets trimmed, so matching whitespace only ensures that this
     106        // service will never be selected automatically.
     107        services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
     108    }
     109
     110    public void actionPerformed(ActionEvent e) {
     111        JPanel panel = new JPanel(new GridBagLayout());
     112        panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
     113
     114        JTextField tfWmsUrl = new JTextField(30);
     115
     116        String clip = getClipboardContents();
     117        ButtonGroup group = new ButtonGroup();
     118
     119        JRadioButton firstBtn = null;
     120        for(RectifierService s : services) {
     121            JRadioButton serviceBtn = new JRadioButton(s.name);
     122            if(firstBtn == null)
     123                firstBtn = serviceBtn;
     124            // Checks clipboard contents against current service if no match has been found yet.
     125            // If the contents match, they will be inserted into the text field and the corresponding
     126            // service will be pre-selected.
     127            if(!clip.equals("") && tfWmsUrl.getText().equals("")
     128                    && (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
     129                serviceBtn.setSelected(true);
     130                tfWmsUrl.setText(clip);
     131            }
     132            s.btn = serviceBtn;
     133            group.add(serviceBtn);
     134            if(!s.url.equals("")) {
     135                panel.add(serviceBtn, GBC.std());
     136                panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
     137            } else
     138                panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
     139        }
     140
     141        // Fallback in case no match was found
     142        if(tfWmsUrl.getText().equals("") && firstBtn != null)
     143            firstBtn.setSelected(true);
     144
     145        panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
     146        panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
     147
     148        ExtendedDialog diag = new ExtendedDialog(Main.parent,
     149                tr("Add Rectified Image"),
     150
     151                new String[] {tr("Add Rectified Image"), tr("Cancel")});
     152        diag.setContent(panel);
     153        diag.setButtonIcons(new String[] {"OLmarker.png", "cancel.png"});
     154
     155        // This repeatedly shows the dialog in case there has been an error.
     156        // The loop is break;-ed if the users cancels
     157        outer: while(true) {
     158            diag.showDialog();
     159            int answer = diag.getValue();
     160            // Break loop when the user cancels
     161            if(answer != 1)
     162                break;
     163
     164            String text = tfWmsUrl.getText().trim();
     165            // Loop all services until we find the selected one
     166            for(RectifierService s : services) {
     167                if(!s.isSelected())
     168                    continue;
     169
     170                // We've reached the custom WMS URL service
     171                // Just set the URL and hope everything works out
     172                if(s.wmsUrl.equals("")) {
     173                    addWMSLayer(s.name + " (" + text + ")", text);
     174                    break outer;
     175                }
     176
     177                // First try to match if the entered string as an URL
     178                Matcher m = s.urlRegEx.matcher(text);
     179                if(m.find()) {
     180                    String id = m.group(1);
     181                    String newURL = s.wmsUrl.replaceAll("__s__", id);
     182                    String title = s.name + " (" + id + ")";
     183                    addWMSLayer(title, newURL);
     184                    break outer;
     185                }
     186                // If not, look if it's a valid ID for the selected service
     187                if(s.idValidator.matcher(text).matches()) {
     188                    String newURL = s.wmsUrl.replaceAll("__s__", text);
     189                    String title = s.name + " (" + text + ")";
     190                    addWMSLayer(title, newURL);
     191                    break outer;
     192                }
     193
     194                // We've found the selected service, but the entered string isn't suitable for
     195                // it. So quit checking the other radio buttons
     196                break;
     197            }
     198
     199            // and display an error message. The while(true) ensures that the dialog pops up again
     200            JOptionPane.showMessageDialog(Main.parent,
     201                    tr("Couldn't match the entered link or id to the selected service. Please try again."),
     202                    tr("No valid WMS URL or id"),
     203                    JOptionPane.ERROR_MESSAGE);
     204            diag.setVisible(true);
     205        }
     206    }
     207
     208    /**
     209     * Adds a WMS Layer with given title and URL
     210     * @param title: Name of the layer as it will shop up in the layer manager
     211     * @param url: URL to the WMS server
     212     */
     213    private void addWMSLayer(String title, String url) {
     214        Main.main.addLayer(new WMSLayer(new WMSInfo(title, url)));
     215    }
     216
     217    /**
     218     * Helper function that extracts a String from the Clipboard if available.
     219     * Returns an empty String otherwise
     220     * @return String Clipboard contents if available
     221     */
     222    private String getClipboardContents() {
     223        String result = "";
     224        Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
     225
     226        if(contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor))
     227            return "";
     228
     229        try {
     230            result = (String)contents.getTransferData(DataFlavor.stringFlavor);
     231        } catch(Exception ex) {
     232            return "";
     233        }
     234        return result.trim();
     235    }
    247236}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSAdjustAction.java

    r22761 r23207  
    3131
    3232public class WMSAdjustAction extends MapMode implements MouseListener, MouseMotionListener{
    33         //static private final Logger logger = Logger.getLogger(WMSAdjustAction.class.getName());
    34 
    35         GeorefImage selectedImage;
    36         boolean mouseDown;
    37         EastNorth prevEastNorth;
    38         private WMSLayer adjustingLayer;
    39 
    40         public WMSAdjustAction(MapFrame mapFrame) {
    41                 super(tr("Adjust WMS"), "adjustwms",
    42                                 tr("Adjust the position of the selected WMS layer"), mapFrame,
    43                                 ImageProvider.getCursor("normal", "move"));
    44         }
    45 
    46 
    47 
    48         @Override public void enterMode() {
    49                 super.enterMode();
    50                 if (!hasWMSLayersToAdjust()) {
    51                         warnNoWMSLayers();
    52                         return;
    53                 }
    54                 List<WMSLayer> wmsLayers = Main.map.mapView.getLayersOfType(WMSLayer.class);
    55                 if (wmsLayers.size() == 1) {
    56                         adjustingLayer = wmsLayers.get(0);
    57                 } else {
    58                         adjustingLayer = (WMSLayer)askAdjustLayer(Main.map.mapView.getLayersOfType(WMSLayer.class));
    59                 }
    60                 if (adjustingLayer == null)
    61                         return;
    62                 if (!adjustingLayer.isVisible()) {
    63                         adjustingLayer.setVisible(true);
    64                 }
    65                 Main.map.mapView.addMouseListener(this);
    66                 Main.map.mapView.addMouseMotionListener(this);
    67         }
    68 
    69         @Override public void exitMode() {
    70                 super.exitMode();
    71                 Main.map.mapView.removeMouseListener(this);
    72                 Main.map.mapView.removeMouseMotionListener(this);
    73                 adjustingLayer = null;
    74         }
    75 
    76         @Override public void mousePressed(MouseEvent e) {
    77                 if (e.getButton() != MouseEvent.BUTTON1)
    78                         return;
    79 
    80                 if (adjustingLayer.isVisible()) {
    81                         prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
    82                         selectedImage = adjustingLayer.findImage(prevEastNorth);
    83                         if(selectedImage!=null) {
    84                                 Main.map.mapView.setCursor
    85                                 (Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    86                         }
    87                 }
    88         }
    89 
    90         @Override public void mouseDragged(MouseEvent e) {
    91                 if(selectedImage!=null) {
    92                         EastNorth eastNorth=
    93                                 Main.map.mapView.getEastNorth(e.getX(),e.getY());
    94                         adjustingLayer.displace(
    95                                         eastNorth.east()-prevEastNorth.east(),
    96                                         eastNorth.north()-prevEastNorth.north()
    97                         );
    98                         prevEastNorth = eastNorth;
    99                         Main.map.mapView.repaint();
    100                 }
    101         }
    102 
    103         @Override public void mouseReleased(MouseEvent e) {
    104                 Main.map.mapView.repaint();
    105                 Main.map.mapView.setCursor(Cursor.getDefaultCursor());
    106                 selectedImage = null;
    107                 prevEastNorth = null;
    108         }
    109 
    110         @Override
    111         public void mouseEntered(MouseEvent e) {
    112         }
    113 
    114         @Override
    115         public void mouseExited(MouseEvent e) {
    116         }
    117 
    118         @Override
    119         public void mouseMoved(MouseEvent e) {
    120         }
    121 
    122         @Override public void mouseClicked(MouseEvent e) {
    123         }
    124 
    125         @Override public boolean layerIsSupported(Layer l) {
    126                 return hasWMSLayersToAdjust();
    127         }
    128 
    129         /**
    130         * the list cell renderer used to render layer list entries
    131         *
    132         */
    133         static public class LayerListCellRenderer extends DefaultListCellRenderer {
    134 
    135                 protected boolean isActiveLayer(Layer layer) {
    136                         if (Main.map == null)
    137                                 return false;
    138                         if (Main.map.mapView == null)
    139                                 return false;
    140                         return Main.map.mapView.getActiveLayer() == layer;
    141                 }
    142 
    143                 @Override
    144                 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
    145                                 boolean cellHasFocus) {
    146                         Layer layer = (Layer) value;
    147                         JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected,
    148                                         cellHasFocus);
    149                         Icon icon = layer.getIcon();
    150                         label.setIcon(icon);
    151                         label.setToolTipText(layer.getToolTipText());
    152                         return label;
    153                 }
    154         }
    155 
    156         /**
    157         * Prompts the user with a list of WMS layers which can be adjusted
    158         *
    159         * @param adjustableLayers the list of adjustable layers
    160         * @return  the selected layer; null, if no layer was selected
    161         */
    162         protected Layer askAdjustLayer(List<? extends Layer> adjustableLayers) {
    163                 JComboBox layerList = new JComboBox();
    164                 layerList.setRenderer(new LayerListCellRenderer());
    165                 layerList.setModel(new DefaultComboBoxModel(adjustableLayers.toArray()));
    166                 layerList.setSelectedIndex(0);
    167 
    168                 JPanel pnl = new JPanel();
    169                 pnl.setLayout(new GridBagLayout());
    170                 pnl.add(new JLabel(tr("Please select the WMS layer to adjust.")), GBC.eol());
    171                 pnl.add(layerList, GBC.eol());
    172 
    173                 ExtendedDialog diag = new ExtendedDialog(
    174                                 Main.parent,
    175                                 tr("Select WMS layer"),
    176                                 new String[] { tr("Start adjusting"),tr("Cancel") }
    177                 );
    178                 diag.setContent(pnl);
    179                 diag.setButtonIcons(new String[] { "mapmode/adjustwms", "cancel" });
    180                 diag.showDialog();
    181                 int decision = diag.getValue();
    182                 if (decision != 1)
    183                         return null;
    184                 Layer adjustLayer = (Layer) layerList.getSelectedItem();
    185                 return adjustLayer;
    186         }
    187 
    188         /**
    189         * Displays a warning message if there are no WMS layers to adjust
    190         *
    191         */
    192         protected void warnNoWMSLayers() {
    193                 JOptionPane.showMessageDialog(
    194                                 Main.parent,
    195                                 tr("There are currently no WMS layer to adjust."),
    196                                 tr("No layers to adjust"),
    197                                 JOptionPane.WARNING_MESSAGE
    198                 );
    199         }
    200 
    201         /**
    202         * Replies true if there is at least one WMS layer
    203         *
    204         * @return true if there is at least one WMS layer
    205         */
    206         protected boolean hasWMSLayersToAdjust() {
    207                 if (Main.map == null) return false;
    208                 if (Main.map.mapView == null) return false;
    209                 return ! Main.map.mapView.getLayersOfType(WMSLayer.class).isEmpty();
    210         }
    211 
    212         @Override
    213         protected void updateEnabledState() {
    214                 setEnabled(hasWMSLayersToAdjust());
    215         }
     33    //static private final Logger logger = Logger.getLogger(WMSAdjustAction.class.getName());
     34
     35    GeorefImage selectedImage;
     36    boolean mouseDown;
     37    EastNorth prevEastNorth;
     38    private WMSLayer adjustingLayer;
     39
     40    public WMSAdjustAction(MapFrame mapFrame) {
     41        super(tr("Adjust WMS"), "adjustwms",
     42                tr("Adjust the position of the selected WMS layer"), mapFrame,
     43                ImageProvider.getCursor("normal", "move"));
     44    }
     45
     46
     47
     48    @Override public void enterMode() {
     49        super.enterMode();
     50        if (!hasWMSLayersToAdjust()) {
     51            warnNoWMSLayers();
     52            return;
     53        }
     54        List<WMSLayer> wmsLayers = Main.map.mapView.getLayersOfType(WMSLayer.class);
     55        if (wmsLayers.size() == 1) {
     56            adjustingLayer = wmsLayers.get(0);
     57        } else {
     58            adjustingLayer = (WMSLayer)askAdjustLayer(Main.map.mapView.getLayersOfType(WMSLayer.class));
     59        }
     60        if (adjustingLayer == null)
     61            return;
     62        if (!adjustingLayer.isVisible()) {
     63            adjustingLayer.setVisible(true);
     64        }
     65        Main.map.mapView.addMouseListener(this);
     66        Main.map.mapView.addMouseMotionListener(this);
     67    }
     68
     69    @Override public void exitMode() {
     70        super.exitMode();
     71        Main.map.mapView.removeMouseListener(this);
     72        Main.map.mapView.removeMouseMotionListener(this);
     73        adjustingLayer = null;
     74    }
     75
     76    @Override public void mousePressed(MouseEvent e) {
     77        if (e.getButton() != MouseEvent.BUTTON1)
     78            return;
     79
     80        if (adjustingLayer.isVisible()) {
     81            prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
     82            selectedImage = adjustingLayer.findImage(prevEastNorth);
     83            if(selectedImage!=null) {
     84                Main.map.mapView.setCursor
     85                (Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
     86            }
     87        }
     88    }
     89
     90    @Override public void mouseDragged(MouseEvent e) {
     91        if(selectedImage!=null) {
     92            EastNorth eastNorth=
     93                Main.map.mapView.getEastNorth(e.getX(),e.getY());
     94            adjustingLayer.displace(
     95                    eastNorth.east()-prevEastNorth.east(),
     96                    eastNorth.north()-prevEastNorth.north()
     97            );
     98            prevEastNorth = eastNorth;
     99            Main.map.mapView.repaint();
     100        }
     101    }
     102
     103    @Override public void mouseReleased(MouseEvent e) {
     104        Main.map.mapView.repaint();
     105        Main.map.mapView.setCursor(Cursor.getDefaultCursor());
     106        selectedImage = null;
     107        prevEastNorth = null;
     108    }
     109
     110    @Override
     111    public void mouseEntered(MouseEvent e) {
     112    }
     113
     114    @Override
     115    public void mouseExited(MouseEvent e) {
     116    }
     117
     118    @Override
     119    public void mouseMoved(MouseEvent e) {
     120    }
     121
     122    @Override public void mouseClicked(MouseEvent e) {
     123    }
     124
     125    @Override public boolean layerIsSupported(Layer l) {
     126        return hasWMSLayersToAdjust();
     127    }
     128
     129    /**
     130    * the list cell renderer used to render layer list entries
     131    *
     132    */
     133    static public class LayerListCellRenderer extends DefaultListCellRenderer {
     134
     135        protected boolean isActiveLayer(Layer layer) {
     136            if (Main.map == null)
     137                return false;
     138            if (Main.map.mapView == null)
     139                return false;
     140            return Main.map.mapView.getActiveLayer() == layer;
     141        }
     142
     143        @Override
     144        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
     145                boolean cellHasFocus) {
     146            Layer layer = (Layer) value;
     147            JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected,
     148                    cellHasFocus);
     149            Icon icon = layer.getIcon();
     150            label.setIcon(icon);
     151            label.setToolTipText(layer.getToolTipText());
     152            return label;
     153        }
     154    }
     155
     156    /**
     157    * Prompts the user with a list of WMS layers which can be adjusted
     158    *
     159    * @param adjustableLayers the list of adjustable layers
     160    * @return  the selected layer; null, if no layer was selected
     161    */
     162    protected Layer askAdjustLayer(List<? extends Layer> adjustableLayers) {
     163        JComboBox layerList = new JComboBox();
     164        layerList.setRenderer(new LayerListCellRenderer());
     165        layerList.setModel(new DefaultComboBoxModel(adjustableLayers.toArray()));
     166        layerList.setSelectedIndex(0);
     167
     168        JPanel pnl = new JPanel();
     169        pnl.setLayout(new GridBagLayout());
     170        pnl.add(new JLabel(tr("Please select the WMS layer to adjust.")), GBC.eol());
     171        pnl.add(layerList, GBC.eol());
     172
     173        ExtendedDialog diag = new ExtendedDialog(
     174                Main.parent,
     175                tr("Select WMS layer"),
     176                new String[] { tr("Start adjusting"),tr("Cancel") }
     177        );
     178        diag.setContent(pnl);
     179        diag.setButtonIcons(new String[] { "mapmode/adjustwms", "cancel" });
     180        diag.showDialog();
     181        int decision = diag.getValue();
     182        if (decision != 1)
     183            return null;
     184        Layer adjustLayer = (Layer) layerList.getSelectedItem();
     185        return adjustLayer;
     186    }
     187
     188    /**
     189    * Displays a warning message if there are no WMS layers to adjust
     190    *
     191    */
     192    protected void warnNoWMSLayers() {
     193        JOptionPane.showMessageDialog(
     194                Main.parent,
     195                tr("There are currently no WMS layer to adjust."),
     196                tr("No layers to adjust"),
     197                JOptionPane.WARNING_MESSAGE
     198        );
     199    }
     200
     201    /**
     202    * Replies true if there is at least one WMS layer
     203    *
     204    * @return true if there is at least one WMS layer
     205    */
     206    protected boolean hasWMSLayersToAdjust() {
     207        if (Main.map == null) return false;
     208        if (Main.map.mapView == null) return false;
     209        return ! Main.map.mapView.getLayersOfType(WMSLayer.class).isEmpty();
     210    }
     211
     212    @Override
     213    protected void updateEnabledState() {
     214        setEnabled(hasWMSLayersToAdjust());
     215    }
    216216}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSDownloadAction.java

    r22677 r23207  
    1010public class WMSDownloadAction extends JosmAction {
    1111
    12         private final WMSInfo info;
     12    private final WMSInfo info;
    1313
    14         public WMSDownloadAction(WMSInfo info) {
    15                 super(info.name, "wmsmenu", tr("Download WMS tile from {0}",info.name), null, false);
    16                 putValue("toolbar", "wms_" + info.name);
    17                 this.info = info;
    18         }
     14    public WMSDownloadAction(WMSInfo info) {
     15        super(info.getMenuName(), "wmsmenu", tr("Download WMS tile from {0}",info.name), null, false);
     16        putValue("toolbar", "wms_" + info.getToolbarName());
     17        this.info = info;
     18    }
    1919
    20         public void actionPerformed(ActionEvent e) {
    21                 //System.out.println(info.url);
    22 
    23                 WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
    24                 Main.main.addLayer(wmsLayer);
    25         }
    26 
    27         public static WMSLayer getLayer(WMSInfo info) {
    28                 // FIXME: move this to WMSPlugin/WMSInfo/preferences.
    29                 WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
    30                 Main.main.addLayer(wmsLayer);
    31                 return wmsLayer;
    32         }
     20    public void actionPerformed(ActionEvent e) {
     21        WMSLayer wmsLayer = new WMSLayer(info);
     22        Main.main.addLayer(wmsLayer);
     23    }
    3324};
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSGrabber.java

    r22712 r23207  
    3636
    3737public class WMSGrabber extends Grabber {
    38         public static boolean isUrlWithPatterns(String url) {
    39                 return url != null && url.contains("{") && url.contains("}");
    40         }
    41 
    42         protected String baseURL;
    43         private final boolean urlWithPatterns;
    44 
    45         WMSGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
    46                 super(mv, layer, cache);
    47                 this.baseURL = layer.baseURL;
    48                 /* URL containing placeholders? */
    49                 urlWithPatterns = isUrlWithPatterns(baseURL);
    50         }
    51 
    52         @Override
    53         void fetch(WMSRequest request) throws Exception{
    54                 URL url = null;
    55                 try {
    56                         url = getURL(
    57                                         b.min.east(), b.min.north(),
    58                                         b.max.east(), b.max.north(),
    59                                         width(), height());
    60                         request.finish(State.IMAGE, grab(url));
    61 
    62                 } catch(Exception e) {
    63                         e.printStackTrace();
    64                         throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
    65                 }
    66         }
    67 
    68         public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
    69                         new DecimalFormatSymbols(Locale.US));
    70 
    71         protected URL getURL(double w, double s,double e,double n,
    72                         int wi, int ht) throws MalformedURLException {
    73                 String myProj = Main.proj.toCode();
    74                 if(Main.proj instanceof Mercator) // don't use mercator code directly
    75                 {
    76                         LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
    77                         LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
    78                         myProj = "EPSG:4326";
    79                         s = sw.lat();
    80                         w = sw.lon();
    81                         n = ne.lat();
    82                         e = ne.lon();
    83                 }
    84 
    85                 String str = baseURL;
    86                 String bbox = latLonFormat.format(w) + ","
    87                 + latLonFormat.format(s) + ","
    88                 + latLonFormat.format(e) + ","
    89                 + latLonFormat.format(n);
    90 
    91                 if (urlWithPatterns) {
    92                         str = str.replaceAll("\\{proj\\}", myProj)
    93                         .replaceAll("\\{bbox\\}", bbox)
    94                         .replaceAll("\\{w\\}", latLonFormat.format(w))
    95                         .replaceAll("\\{s\\}", latLonFormat.format(s))
    96                         .replaceAll("\\{e\\}", latLonFormat.format(e))
    97                         .replaceAll("\\{n\\}", latLonFormat.format(n))
    98                         .replaceAll("\\{width\\}", String.valueOf(wi))
    99                         .replaceAll("\\{height\\}", String.valueOf(ht));
    100                 } else {
    101                         str += "bbox=" + bbox
    102                         + getProjection(baseURL, false)
    103                         + "&width=" + wi + "&height=" + ht;
    104                         if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
    105                                 System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
    106                                 System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
    107                                 System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
    108                         }
    109                 }
    110                 return new URL(str.replace(" ", "%20"));
    111         }
    112 
    113         static public String getProjection(String baseURL, Boolean warn)
    114         {
    115                 String projname = Main.proj.toCode();
    116                 if(Main.proj instanceof Mercator) // don't use mercator code
    117                         projname = "EPSG:4326";
    118                 String res = "";
    119                 try
    120                 {
    121                         Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
    122                         if(m.matches())
    123                         {
    124                                 projname = projname.toLowerCase();
    125                                 if(!projname.equals(m.group(1)) && warn)
    126                                 {
    127                                         JOptionPane.showMessageDialog(Main.parent,
    128                                                         tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
    129                                                                         + "This may lead to wrong coordinates.",
    130                                                                         m.group(1), projname),
    131                                                                         tr("Warning"),
    132                                                                         JOptionPane.WARNING_MESSAGE);
    133                                 }
    134                         }
    135                         else
    136                                 res ="&srs="+projname;
    137                 }
    138                 catch(Exception e)
    139                 {
    140                 }
    141                 return res;
    142         }
    143 
    144         @Override
    145         public boolean loadFromCache(WMSRequest request) {
    146                 URL url = null;
    147                 try{
    148                         url = getURL(
    149                                         b.min.east(), b.min.north(),
    150                                         b.max.east(), b.max.north(),
    151                                         width(), height());
    152                 } catch(Exception e) {
    153                         return false;
    154                 }
    155                 BufferedImage cached = cache.getImg(url.toString());
    156                 if((!request.isReal() && !layer.hasAutoDownload()) || cached != null){
    157                         if(cached == null){
    158                                 request.finish(State.NOT_IN_CACHE, null);
    159                                 return true;
    160                         }
    161                         request.finish(State.IMAGE, cached);
    162                         return true;
    163                 }
    164                 return false;
    165         }
    166 
    167         protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
    168                 System.out.println("Grabbing WMS " + url);
    169 
    170                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    171                 if(layer.cookies != null && !layer.cookies.equals(""))
    172                         conn.setRequestProperty("Cookie", layer.cookies);
    173                 conn.setRequestProperty("User-Agent", Main.pref.get("wmsplugin.user_agent", Version.getInstance().getAgentString()));
    174                 conn.setConnectTimeout(Main.pref.getInteger("wmsplugin.timeout.connect", 30) * 1000);
    175                 conn.setReadTimeout(Main.pref.getInteger("wmsplugin.timeout.read", 30) * 1000);
    176 
    177                 String contentType = conn.getHeaderField("Content-Type");
    178                 if( conn.getResponseCode() != 200
    179                                 || contentType != null && !contentType.startsWith("image") ) {
    180                         throw new IOException(readException(conn));
    181                 }
    182 
    183                 InputStream is = new ProgressInputStream(conn, null);
    184                 BufferedImage img = ImageIO.read(is);
    185                 is.close();
    186 
    187                 cache.saveImg(url.toString(), img);
    188                 return img;
    189         }
    190 
    191         protected String readException(URLConnection conn) throws IOException {
    192                 StringBuilder exception = new StringBuilder();
    193                 InputStream in = conn.getInputStream();
    194                 BufferedReader br = new BufferedReader(new InputStreamReader(in));
    195 
    196                 String line = null;
    197                 while( (line = br.readLine()) != null) {
    198                         // filter non-ASCII characters and control characters
    199                         exception.append(line.replaceAll("[^\\p{Print}]", ""));
    200                         exception.append('\n');
    201                 }
    202                 return exception.toString();
    203         }
     38    public static boolean isUrlWithPatterns(String url) {
     39        return url != null && url.contains("{") && url.contains("}");
     40    }
     41
     42    protected String baseURL;
     43    private final boolean urlWithPatterns;
     44
     45    WMSGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
     46        super(mv, layer, cache);
     47        this.baseURL = layer.info.url;
     48        /* URL containing placeholders? */
     49        urlWithPatterns = isUrlWithPatterns(baseURL);
     50    }
     51
     52    @Override
     53    void fetch(WMSRequest request) throws Exception{
     54        URL url = null;
     55        try {
     56            url = getURL(
     57                    b.min.east(), b.min.north(),
     58                    b.max.east(), b.max.north(),
     59                    width(), height());
     60            request.finish(State.IMAGE, grab(url));
     61
     62        } catch(Exception e) {
     63            e.printStackTrace();
     64            throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
     65        }
     66    }
     67
     68    public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
     69            new DecimalFormatSymbols(Locale.US));
     70
     71    protected URL getURL(double w, double s,double e,double n,
     72            int wi, int ht) throws MalformedURLException {
     73        String myProj = Main.proj.toCode();
     74        if(Main.proj instanceof Mercator) // don't use mercator code directly
     75        {
     76            LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
     77            LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
     78            myProj = "EPSG:4326";
     79            s = sw.lat();
     80            w = sw.lon();
     81            n = ne.lat();
     82            e = ne.lon();
     83        }
     84
     85        String str = baseURL;
     86        String bbox = latLonFormat.format(w) + ","
     87        + latLonFormat.format(s) + ","
     88        + latLonFormat.format(e) + ","
     89        + latLonFormat.format(n);
     90
     91        if (urlWithPatterns) {
     92            str = str.replaceAll("\\{proj\\}", myProj)
     93            .replaceAll("\\{bbox\\}", bbox)
     94            .replaceAll("\\{w\\}", latLonFormat.format(w))
     95            .replaceAll("\\{s\\}", latLonFormat.format(s))
     96            .replaceAll("\\{e\\}", latLonFormat.format(e))
     97            .replaceAll("\\{n\\}", latLonFormat.format(n))
     98            .replaceAll("\\{width\\}", String.valueOf(wi))
     99            .replaceAll("\\{height\\}", String.valueOf(ht));
     100        } else {
     101            str += "bbox=" + bbox
     102            + getProjection(baseURL, false)
     103            + "&width=" + wi + "&height=" + ht;
     104            if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
     105                System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
     106                System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
     107                System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
     108            }
     109        }
     110        return new URL(str.replace(" ", "%20"));
     111    }
     112
     113    static public String getProjection(String baseURL, Boolean warn)
     114    {
     115        String projname = Main.proj.toCode();
     116        if(Main.proj instanceof Mercator) // don't use mercator code
     117            projname = "EPSG:4326";
     118        String res = "";
     119        try
     120        {
     121            Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
     122            if(m.matches())
     123            {
     124                projname = projname.toLowerCase();
     125                if(!projname.equals(m.group(1)) && warn)
     126                {
     127                    JOptionPane.showMessageDialog(Main.parent,
     128                            tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
     129                                    + "This may lead to wrong coordinates.",
     130                                    m.group(1), projname),
     131                                    tr("Warning"),
     132                                    JOptionPane.WARNING_MESSAGE);
     133                }
     134            }
     135            else
     136                res ="&srs="+projname;
     137        }
     138        catch(Exception e)
     139        {
     140        }
     141        return res;
     142    }
     143
     144    @Override
     145    public boolean loadFromCache(WMSRequest request) {
     146        URL url = null;
     147        try{
     148            url = getURL(
     149                    b.min.east(), b.min.north(),
     150                    b.max.east(), b.max.north(),
     151                    width(), height());
     152        } catch(Exception e) {
     153            return false;
     154        }
     155        BufferedImage cached = cache.getImg(url.toString());
     156        if((!request.isReal() && !layer.hasAutoDownload()) || cached != null){
     157            if(cached == null){
     158                request.finish(State.NOT_IN_CACHE, null);
     159                return true;
     160            }
     161            request.finish(State.IMAGE, cached);
     162            return true;
     163        }
     164        return false;
     165    }
     166
     167    protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
     168        System.out.println("Grabbing WMS " + url);
     169
     170        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
     171        if(layer.info.cookies != null && !layer.info.cookies.equals(""))
     172            conn.setRequestProperty("Cookie", layer.info.cookies);
     173        conn.setRequestProperty("User-Agent", Main.pref.get("wmsplugin.user_agent", Version.getInstance().getAgentString()));
     174        conn.setConnectTimeout(Main.pref.getInteger("wmsplugin.timeout.connect", 30) * 1000);
     175        conn.setReadTimeout(Main.pref.getInteger("wmsplugin.timeout.read", 30) * 1000);
     176
     177        String contentType = conn.getHeaderField("Content-Type");
     178        if( conn.getResponseCode() != 200
     179                || contentType != null && !contentType.startsWith("image") ) {
     180            throw new IOException(readException(conn));
     181        }
     182
     183        InputStream is = new ProgressInputStream(conn, null);
     184        BufferedImage img = ImageIO.read(is);
     185        is.close();
     186
     187        cache.saveImg(url.toString(), img);
     188        return img;
     189    }
     190
     191    protected String readException(URLConnection conn) throws IOException {
     192        StringBuilder exception = new StringBuilder();
     193        InputStream in = conn.getInputStream();
     194        BufferedReader br = new BufferedReader(new InputStreamReader(in));
     195
     196        String line = null;
     197        while( (line = br.readLine()) != null) {
     198            // filter non-ASCII characters and control characters
     199            exception.append(line.replaceAll("[^\\p{Print}]", ""));
     200            exception.append('\n');
     201        }
     202        return exception.toString();
     203    }
    204204}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSInfo.java

    r19417 r23207  
    11package wmsplugin;
     2
     3import java.util.ArrayList;
     4import java.util.Collection;
    25
    36import org.openstreetmap.josm.Main;
     
    1114
    1215    String name;
    13     String url;
    14     String cookies;
    15     int prefid;
     16    String url=null;
     17    String cookies = null;
     18    boolean html = false;
     19    double pixelPerDegree = 0.0;
    1620
    17     public WMSInfo(String name, String url, int prefid) {
    18         this(name, url, null, prefid);
     21    public WMSInfo(String name) {
     22        this.name=name;
    1923    }
    2024
    21     public WMSInfo(String name, String url, String cookies, int prefid) {
     25    public WMSInfo(String name, String url) {
    2226        this.name=name;
    23         this.url=url;
    24         this.cookies=cookies;
    25         this.prefid=prefid;
     27        setURL(url);
    2628    }
    2729
    28     public void save() {
    29         Main.pref.put("wmsplugin.url." + prefid + ".name", name);
    30         Main.pref.put("wmsplugin.url." + prefid + ".url", url);
     30    public WMSInfo(String name, String url, String cookies) {
     31        this.name=name;
     32        setURL(url);
     33        this.cookies=cookies;
     34    }
     35
     36    public WMSInfo(String name, String url, String cookies, double pixelPerDegree) {
     37        this.name=name;
     38        setURL(url);
     39        this.cookies=cookies;
     40        this.pixelPerDegree=pixelPerDegree;
     41    }
     42
     43    public ArrayList<String> getInfoArray() {
     44        String e2 = null;
     45        String e3 = null;
     46        String e4 = null;
     47        if(url != null && !url.isEmpty()) e2 = getFullURL();
     48        if(cookies != null && !cookies.isEmpty()) e3 = cookies;
     49        if(pixelPerDegree != 0.0) e4 = String.valueOf(pixelPerDegree);
     50        if(e4 != null && e3 == null) e3 = "";
     51        if(e3 != null && e2 == null) e2 = "";
     52
     53        ArrayList<String> res = new ArrayList<String>();
     54        res.add(name);
     55        if(e2 != null) res.add(e2);
     56        if(e3 != null) res.add(e3);
     57        if(e4 != null) res.add(e4);
     58        return res;
     59    }
     60
     61    public WMSInfo(Collection<String> list) {
     62        ArrayList<String> array = new ArrayList<String>(list);
     63        this.name=array.get(0);
     64        if(array.size() >= 2) setURL(array.get(1));
     65        if(array.size() >= 3) this.cookies=array.get(2);
     66        if(array.size() >= 4) this.pixelPerDegree=Double.valueOf(array.get(3));
     67    }
     68
     69    public WMSInfo(WMSInfo i) {
     70        this.name=i.name;
     71        this.url=i.url;
     72        this.cookies=i.cookies;
     73        this.html=i.html;
     74        this.pixelPerDegree=i.pixelPerDegree;
    3175    }
    3276
     
    3781            i = url.compareTo(in.url);
    3882        if(i == 0)
    39             i = prefid-in.prefid;
     83            i = Double.compare(pixelPerDegree, in.pixelPerDegree);
    4084        return i;
    4185    }
     86
     87    public boolean equalsBaseValues(WMSInfo in)
     88    {
     89        return url.equals(in.url);
     90    }
     91
     92    public void setPixelPerDegree(double ppd) {
     93        this.pixelPerDegree = ppd;
     94    }
     95
     96    public void setURL(String url) {
     97        if(url.startsWith("html:")) {
     98            this.url = url.substring(5);
     99            html = true;
     100        } else {
     101            this.url = url;
     102        }
     103    }
     104
     105    public String getFullURL() {
     106        return html ? "html:" + url : url;
     107    }
     108
     109    public String getToolbarName()
     110    {
     111        String res = name;
     112        if(pixelPerDegree != 0.0)
     113            res += "#PPD="+pixelPerDegree;
     114        return res;
     115    }
     116
     117    public String getMenuName()
     118    {
     119        String res = name;
     120        if(pixelPerDegree != 0.0)
     121            res += " ("+pixelPerDegree+")";
     122        return res;
     123    }
    42124}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSLayer.java

    r22954 r23207  
    5454public class WMSLayer extends Layer implements PreferenceChangedListener {
    5555
    56         protected static final Icon icon =
    57                 new ImageIcon(Toolkit.getDefaultToolkit().createImage(WMSPlugin.class.getResource("/images/wms_small.png")));
    58 
    59         public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("wmsplugin.alpha_channel", true);
    60 
    61         public int messageNum = 5; //limit for messages per layer
    62         protected MapView mv;
    63         protected String resolution;
    64         protected int imageSize = 500;
    65         protected int dax = 10;
    66         protected int day = 10;
    67         protected int daStep = 5;
    68         protected int minZoom = 3;
    69 
    70         protected double dx = 0.0;
    71         protected double dy = 0.0;
    72 
    73         protected double pixelPerDegree;
    74         protected GeorefImage[][] images;
    75         protected String baseURL;
    76         protected String cookies;
    77         protected final int serializeFormatVersion = 5;
    78         protected boolean autoDownloadEnabled = true;
    79         protected boolean settingsChanged;
    80 
    81         // Image index boundary for current view
    82         private volatile int bminx;
    83         private volatile int bminy;
    84         private volatile int bmaxx;
    85         private volatile int bmaxy;
    86         private volatile int leftEdge;
    87         private volatile int bottomEdge;
    88 
    89         // Request queue
    90         private final List<WMSRequest> requestQueue = new ArrayList<WMSRequest>();
    91         private final List<WMSRequest> finishedRequests = new ArrayList<WMSRequest>();
    92         private final Lock requestQueueLock = new ReentrantLock();
    93         private final Condition queueEmpty = requestQueueLock.newCondition();
    94         private final List<Grabber> grabbers = new ArrayList<Grabber>();
    95         private final List<Thread> grabberThreads = new ArrayList<Thread>();
    96         private int threadCount;
    97         private int workingThreadCount;
    98         private boolean canceled;
    99 
    100 
    101         /** set to true if this layer uses an invalid base url */
    102         private boolean usesInvalidUrl = false;
    103         /** set to true if the user confirmed to use an potentially invalid WMS base url */
    104         private boolean isInvalidUrlConfirmed = false;
    105 
    106         public WMSLayer() {
    107                 this(tr("Blank Layer"), null, null);
    108                 initializeImages();
    109                 mv = Main.map.mapView;
    110         }
    111 
    112         public WMSLayer(String name, String baseURL, String cookies) {
    113                 super(name);
    114                 setBackgroundLayer(true); /* set global background variable */
    115                 initializeImages();
    116                 this.baseURL = baseURL;
    117                 this.cookies = cookies;
    118                 WMSGrabber.getProjection(baseURL, true);
    119                 mv = Main.map.mapView;
    120 
    121                 // quick hack to predefine the PixelDensity to reuse the cache
    122                 int codeIndex = getName().indexOf("#PPD=");
    123                 if (codeIndex != -1) {
    124                         pixelPerDegree = Double.valueOf(getName().substring(codeIndex+5));
    125                 } else {
    126                         pixelPerDegree = getPPD();
    127                 }
    128                 resolution = mv.getDist100PixelText();
    129 
    130                 if(baseURL != null)
    131                 {
    132                         startGrabberThreads();
    133                 }
    134                 if (baseURL != null && !baseURL.startsWith("html:") && !WMSGrabber.isUrlWithPatterns(baseURL)) {
    135                         if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
    136                                 if (!confirmMalformedUrl(baseURL)) {
    137                                         System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", baseURL));
    138                                         usesInvalidUrl = true;
    139                                         setName(getName() + tr("(deactivated)"));
    140                                         return;
    141                                 } else {
    142                                         isInvalidUrlConfirmed = true;
    143                                 }
    144                         }
    145                 }
    146 
    147                 Main.pref.addPreferenceChangeListener(this);
    148         }
    149 
    150         public boolean hasAutoDownload(){
    151                 return autoDownloadEnabled;
    152         }
    153 
    154 
    155         @Override
    156         public void destroy() {
    157                 cancelGrabberThreads(false);
    158                 Main.pref.removePreferenceChangeListener(this);
    159         }
    160 
    161         public void initializeImages() {
    162                 GeorefImage[][] old = images;
    163                 images = new GeorefImage[dax][day];
    164                 if (old != null) {
    165                         for (int i=0; i<old.length; i++) {
    166                                 for (int k=0; k<old[i].length; k++) {
    167                                         GeorefImage o = old[i][k];
    168                                         images[modulo(o.getXIndex(),dax)][modulo(o.getYIndex(),day)] = old[i][k];
    169                                 }
    170                         }
    171                 }
    172                 for(int x = 0; x<dax; ++x) {
    173                         for(int y = 0; y<day; ++y) {
    174                                 if (images[x][y] == null) {
    175                                         images[x][y]= new GeorefImage(this);
    176                                 }
    177                         }
    178                 }
    179         }
    180 
    181         @Override public Icon getIcon() {
    182                 return icon;
    183         }
    184 
    185         @Override public String getToolTipText() {
    186                 if(autoDownloadEnabled)
    187                         return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
    188                 else
    189                         return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
    190         }
    191 
    192         @Override public boolean isMergable(Layer other) {
    193                 return false;
    194         }
    195 
    196         @Override public void mergeFrom(Layer from) {
    197         }
    198 
    199         private int modulo (int a, int b) {
    200                 return a % b >= 0 ? a%b : a%b+b;
    201         }
    202 
    203         private boolean zoomIsTooBig() {
    204                 //don't download when it's too outzoomed
    205                 return pixelPerDegree / getPPD() > minZoom;
    206         }
    207 
    208         @Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
    209                 if(baseURL == null) return;
    210                 if (usesInvalidUrl && !isInvalidUrlConfirmed) return;
    211 
    212                 settingsChanged = false;
    213 
    214                 ProjectionBounds bounds = mv.getProjectionBounds();
    215                 bminx= getImageXIndex(bounds.min.east());
    216                 bminy= getImageYIndex(bounds.min.north());
    217                 bmaxx= getImageXIndex(bounds.max.east());
    218                 bmaxy= getImageYIndex(bounds.max.north());
    219 
    220                 leftEdge = (int)(bounds.min.east() * getPPD());
    221                 bottomEdge = (int)(bounds.min.north() * getPPD());
    222 
    223                 if (zoomIsTooBig()) {
    224                         for(int x = bminx; x<=bmaxx; ++x) {
    225                                 for(int y = bminy; y<=bmaxy; ++y) {
    226                                         images[modulo(x,dax)][modulo(y,day)].paint(g, mv, x, y, leftEdge, bottomEdge);
    227                                 }
    228                         }
    229                 } else {
    230                         downloadAndPaintVisible(g, mv, false);
    231                 }
    232         }
    233 
    234         protected boolean confirmMalformedUrl(String url) {
    235                 if (isInvalidUrlConfirmed)
    236                         return true;
    237                 String msg  = tr("<html>The base URL<br>"
    238                                 + "''{0}''<br>"
    239                                 + "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
    240                                 + "This is likely to lead to invalid WMS request. You should check your<br>"
    241                                 + "preference settings.<br>"
    242                                 + "Do you want to fetch WMS tiles anyway?",
    243                                 url);
    244                 String [] options = new String[] {
    245                                 tr("Yes, fetch images"),
    246                                 tr("No, abort")
    247                 };
    248                 int ret = JOptionPane.showOptionDialog(
    249                                 Main.parent,
    250                                 msg,
    251                                 tr("Invalid URL?"),
    252                                 JOptionPane.YES_NO_OPTION,
    253                                 JOptionPane.WARNING_MESSAGE,
    254                                 null,
    255                                 options, options[1]
    256                 );
    257                 switch(ret) {
    258                 case JOptionPane.YES_OPTION: return true;
    259                 default: return false;
    260                 }
    261         }
    262 
    263         public double getPPD(){
    264                 ProjectionBounds bounds = mv.getProjectionBounds();
    265                 return mv.getWidth() / (bounds.max.east() - bounds.min.east());
    266         }
    267 
    268         public void displace(double dx, double dy) {
    269                 settingsChanged = true;
    270                 this.dx += dx;
    271                 this.dy += dy;
    272         }
    273 
    274         public int getImageXIndex(double coord) {
    275                 return (int)Math.floor( ((coord - dx) * pixelPerDegree) / imageSize);
    276         }
    277 
    278         public int getImageYIndex(double coord) {
    279                 return (int)Math.floor( ((coord - dy) * pixelPerDegree) / imageSize);
    280         }
    281 
    282         public int getImageX(int imageIndex) {
    283                 return (int)(imageIndex * imageSize * (getPPD() / pixelPerDegree) + dx * getPPD());
    284         }
    285 
    286         public int getImageY(int imageIndex) {
    287                 return (int)(imageIndex * imageSize * (getPPD() / pixelPerDegree) + dy * getPPD());
    288         }
    289 
    290         public int getImageWidth(int xIndex) {
    291                 int overlap = (int)(WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_EAST.get() * imageSize * getPPD() / pixelPerDegree / 100:0);
    292                 return getImageX(xIndex + 1) - getImageX(xIndex) + overlap;
    293         }
    294 
    295         public int getImageHeight(int yIndex) {
    296                 int overlap = (int)(WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_NORTH.get() * imageSize * getPPD() / pixelPerDegree / 100:0);
    297                 return getImageY(yIndex + 1) - getImageY(yIndex) + overlap;
    298         }
    299 
    300         /**
    301          *
    302          * @return Size of image in original zoom
    303          */
    304         public int getBaseImageWidth() {
    305                 int overlap = (WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_EAST.get() * imageSize / 100:0);
    306                 return imageSize + overlap;
    307         }
    308 
    309         /**
    310          *
    311          * @return Size of image in original zoom
    312          */
    313         public int getBaseImageHeight() {
    314                 int overlap = (WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_NORTH.get() * imageSize / 100:0);
    315                 return imageSize + overlap;
    316         }
    317 
    318 
    319         /**
    320          *
    321          * @param xIndex
    322          * @param yIndex
    323          * @return Real EastNorth of given tile. dx/dy is not counted in
    324          */
    325         public EastNorth getEastNorth(int xIndex, int yIndex) {
    326                 return new EastNorth((xIndex * imageSize) / pixelPerDegree, (yIndex * imageSize) / pixelPerDegree);
    327         }
    328 
    329 
    330         protected void downloadAndPaintVisible(Graphics g, final MapView mv, boolean real){
    331 
    332                 int newDax = dax;
    333                 int newDay = day;
    334 
    335                 if (bmaxx - bminx >= dax || bmaxx - bminx < dax - 2 * daStep) {
    336                         newDax = ((bmaxx - bminx) / daStep + 1) * daStep;
    337                 }
    338 
    339                 if (bmaxy - bminy >= day || bmaxy - bminx < day - 2 * daStep) {
    340                         newDay = ((bmaxy - bminy) / daStep + 1) * daStep;
    341                 }
    342 
    343                 if (newDax != dax || newDay != day) {
    344                         dax = newDax;
    345                         day = newDay;
    346                         initializeImages();
    347                 }
    348 
    349                 for(int x = bminx; x<=bmaxx; ++x) {
    350                         for(int y = bminy; y<=bmaxy; ++y){
    351                                 images[modulo(x,dax)][modulo(y,day)].changePosition(x, y);
    352                         }
    353                 }
    354 
    355                 gatherFinishedRequests();
    356 
    357                 for(int x = bminx; x<=bmaxx; ++x) {
    358                         for(int y = bminy; y<=bmaxy; ++y){
    359                                 GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
    360                                 if (!img.paint(g, mv, x, y, leftEdge, bottomEdge)) {
    361                                         WMSRequest request = new WMSRequest(x, y, pixelPerDegree, real);
    362                                         addRequest(request);
    363                                 }
    364                         }
    365                 }
    366         }
    367 
    368         @Override public void visitBoundingBox(BoundingXYVisitor v) {
    369                 for(int x = 0; x<dax; ++x) {
    370                         for(int y = 0; y<day; ++y)
    371                                 if(images[x][y].getImage() != null){
    372                                         v.visit(images[x][y].getMin());
    373                                         v.visit(images[x][y].getMax());
    374                                 }
    375                 }
    376         }
    377 
    378         @Override public Object getInfoComponent() {
    379                 return getToolTipText();
    380         }
    381 
    382         @Override public Action[] getMenuEntries() {
    383                 return new Action[]{
    384                                 LayerListDialog.getInstance().createActivateLayerAction(this),
    385                                 LayerListDialog.getInstance().createShowHideLayerAction(),
    386                                 LayerListDialog.getInstance().createDeleteLayerAction(),
    387                                 SeparatorLayerAction.INSTANCE,
    388                                 new LoadWmsAction(),
    389                                 new SaveWmsAction(),
    390                                 new BookmarkWmsAction(),
    391                                 SeparatorLayerAction.INSTANCE,
    392                                 new StartStopAction(),
    393                                 new ToggleAlphaAction(),
    394                                 new ChangeResolutionAction(),
    395                                 new ReloadErrorTilesAction(),
    396                                 new DownloadAction(),
    397                                 SeparatorLayerAction.INSTANCE,
    398                                 new LayerListPopup.InfoAction(this)
    399                 };
    400         }
    401 
    402         public GeorefImage findImage(EastNorth eastNorth) {
    403                 int xIndex = getImageXIndex(eastNorth.east());
    404                 int yIndex = getImageYIndex(eastNorth.north());
    405                 GeorefImage result = images[modulo(xIndex, dax)][modulo(yIndex, day)];
    406                 if (result.getXIndex() == xIndex && result.getYIndex() == yIndex) {
    407                         return result;
    408                 } else {
    409                         return null;
    410                 }
    411         }
    412 
    413         /**
    414          *
    415          * @param request
    416          * @return -1 if request is no longer needed, otherwise priority of request (lower number <=> more important request)
    417          */
    418         private int getRequestPriority(WMSRequest request) {
    419                 if (request.getPixelPerDegree() != pixelPerDegree) {
    420                         return -1;
    421                 }
    422                 if (bminx > request.getXIndex()
    423                                 || bmaxx < request.getXIndex()
    424                                 || bminy > request.getYIndex()
    425                                 || bmaxy < request.getYIndex()) {
    426                         return -1;
    427                 }
    428 
    429                 EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
    430                 int mouseX = getImageXIndex(cursorEastNorth.east());
    431                 int mouseY = getImageYIndex(cursorEastNorth.north());
    432                 int dx = request.getXIndex() - mouseX;
    433                 int dy = request.getYIndex() - mouseY;
    434 
    435                 return dx * dx + dy * dy;
    436         }
    437 
    438         public WMSRequest getRequest() {
    439                 requestQueueLock.lock();
    440                 try {
    441                         workingThreadCount--;
    442                         Iterator<WMSRequest> it = requestQueue.iterator();
    443                         while (it.hasNext()) {
    444                                 WMSRequest item = it.next();
    445                                 int priority = getRequestPriority(item);
    446                                 if (priority == -1) {
    447                                         it.remove();
    448                                 } else {
    449                                         item.setPriority(priority);
    450                                 }
    451                         }
    452                         Collections.sort(requestQueue);
    453 
    454                         EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
    455                         int mouseX = getImageXIndex(cursorEastNorth.east());
    456                         int mouseY = getImageYIndex(cursorEastNorth.north());
    457                         boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY;
    458 
    459                         // If there is only one thread left then keep it in case we need to download other tile urgently
    460                         while (!canceled &&
    461                                         (requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) {
    462                                 try {
    463                                         queueEmpty.await();
    464                                 } catch (InterruptedException e) {
    465                                         // Shouldn't happen
    466                                 }
    467                         }
    468 
    469                         workingThreadCount++;
    470                         if (canceled) {
    471                                 return null;
    472                         } else {
    473                                 return requestQueue.remove(0);
    474                         }
    475 
    476                 } finally {
    477                         requestQueueLock.unlock();
    478                 }
    479         }
    480 
    481         public void finishRequest(WMSRequest request) {
    482                 if (request.getState() == null) {
    483                         throw new IllegalArgumentException("Finished request without state");
    484                 }
    485                 requestQueueLock.lock();
    486                 try {
    487                         finishedRequests.add(request);
    488                 } finally {
    489                         requestQueueLock.unlock();
    490                 }
    491         }
    492 
    493         public void addRequest(WMSRequest request) {
    494                 requestQueueLock.lock();
    495                 try {
    496                         if (!requestQueue.contains(request)) {
    497                                 requestQueue.add(request);
    498                                 queueEmpty.signalAll();
    499                         }
    500                 } finally {
    501                         requestQueueLock.unlock();
    502                 }
    503         }
    504 
    505         public boolean requestIsValid(WMSRequest request) {
    506                 return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex();
    507         }
    508 
    509         private void gatherFinishedRequests() {
    510                 requestQueueLock.lock();
    511                 try {
    512                         for (WMSRequest request: finishedRequests) {
    513                                 GeorefImage img = images[modulo(request.getXIndex(),dax)][modulo(request.getYIndex(),day)];
    514                                 if (img.equalPosition(request.getXIndex(), request.getYIndex())) {
    515                                         img.changeImage(request.getState(), request.getImage());
    516                                 }
    517                         }
    518                 } finally {
    519                         finishedRequests.clear();
    520                         requestQueueLock.unlock();
    521                 }
    522         }
    523 
    524         public class DownloadAction extends AbstractAction {
    525                 private static final long serialVersionUID = -7183852461015284020L;
    526                 public DownloadAction() {
    527                         super(tr("Download visible tiles"));
    528                 }
    529                 public void actionPerformed(ActionEvent ev) {
    530                         if (zoomIsTooBig()) {
    531                                 JOptionPane.showMessageDialog(
    532                                                 Main.parent,
    533                                                 tr("The requested area is too big. Please zoom in a little, or change resolution"),
    534                                                 tr("Error"),
    535                                                 JOptionPane.ERROR_MESSAGE
    536                                 );
    537                         } else {
    538                                 downloadAndPaintVisible(mv.getGraphics(), mv, true);
    539                         }
    540                 }
    541         }
    542 
    543         public class ChangeResolutionAction extends AbstractAction {
    544                 public ChangeResolutionAction() {
    545                         super(tr("Change resolution"));
    546                 }
    547                 public void actionPerformed(ActionEvent ev) {
    548                         initializeImages();
    549                         resolution = mv.getDist100PixelText();
    550                         pixelPerDegree = getPPD();
    551                         settingsChanged = true;
    552                         mv.repaint();
    553                 }
    554         }
    555 
    556         public class ReloadErrorTilesAction extends AbstractAction {
    557                 public ReloadErrorTilesAction() {
    558                         super(tr("Reload erroneous tiles"));
    559                 }
    560                 public void actionPerformed(ActionEvent ev) {
    561                         // Delete small files, because they're probably blank tiles.
    562                         // See https://josm.openstreetmap.de/ticket/2307
    563                         WMSPlugin.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
    564 
    565                         for (int x = 0; x < dax; ++x) {
    566                                 for (int y = 0; y < day; ++y) {
    567                                         GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
    568                                         if(img.getState() == State.FAILED){
    569                                                 addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), pixelPerDegree, true));
    570                                                 mv.repaint();
    571                                         }
    572                                 }
    573                         }
    574                 }
    575         }
    576 
    577         public class ToggleAlphaAction extends AbstractAction implements LayerAction {
    578                 public ToggleAlphaAction() {
    579                         super(tr("Alpha channel"));
    580                 }
    581                 public void actionPerformed(ActionEvent ev) {
    582                         JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
    583                         boolean alphaChannel = checkbox.isSelected();
    584                         PROP_ALPHA_CHANNEL.put(alphaChannel);
    585 
    586                         // clear all resized cached instances and repaint the layer
    587                         for (int x = 0; x < dax; ++x) {
    588                                 for (int y = 0; y < day; ++y) {
    589                                         GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
    590                                         img.flushedResizedCachedInstance();
    591                                 }
    592                         }
    593                         mv.repaint();
    594                 }
    595                 public Component createMenuComponent() {
    596                         JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
    597                         item.setSelected(PROP_ALPHA_CHANNEL.get());
    598                         return item;
    599                 }
    600                 public boolean supportLayers(List<Layer> layers) {
    601                         return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
    602                 }
    603         }
    604 
    605         public class SaveWmsAction extends AbstractAction {
    606                 public SaveWmsAction() {
    607                         super(tr("Save WMS layer to file"), ImageProvider.get("save"));
    608                 }
    609                 public void actionPerformed(ActionEvent ev) {
    610                         File f = SaveActionBase.createAndOpenSaveFileChooser(
    611                                         tr("Save WMS layer"), ".wms");
    612                         try {
    613                                 if (f != null) {
    614                                         ObjectOutputStream oos = new ObjectOutputStream(
    615                                                         new FileOutputStream(f)
    616                                         );
    617                                         oos.writeInt(serializeFormatVersion);
    618                                         oos.writeInt(dax);
    619                                         oos.writeInt(day);
    620                                         oos.writeInt(imageSize);
    621                                         oos.writeDouble(pixelPerDegree);
    622                                         oos.writeObject(getName());
    623                                         oos.writeObject(baseURL);
    624                                         oos.writeObject(images);
    625                                         oos.close();
    626                                 }
    627                         } catch (Exception ex) {
    628                                 ex.printStackTrace(System.out);
    629                         }
    630                 }
    631         }
    632 
    633         public class LoadWmsAction extends AbstractAction {
    634                 public LoadWmsAction() {
    635                         super(tr("Load WMS layer from file"), ImageProvider.get("load"));
    636                 }
    637                 public void actionPerformed(ActionEvent ev) {
    638                         JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
    639                                         false, tr("Load WMS layer"), "wms");
    640                         if(fc == null) return;
    641                         File f = fc.getSelectedFile();
    642                         if (f == null) return;
    643                         try
    644                         {
    645                                 FileInputStream fis = new FileInputStream(f);
    646                                 ObjectInputStream ois = new ObjectInputStream(fis);
    647                                 int sfv = ois.readInt();
    648                                 if (sfv != serializeFormatVersion) {
    649                                         JOptionPane.showMessageDialog(Main.parent,
    650                                                         tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
    651                                                         tr("File Format Error"),
    652                                                         JOptionPane.ERROR_MESSAGE);
    653                                         return;
    654                                 }
    655                                 autoDownloadEnabled = false;
    656                                 dax = ois.readInt();
    657                                 day = ois.readInt();
    658                                 imageSize = ois.readInt();
    659                                 pixelPerDegree = ois.readDouble();
    660                                 setName((String)ois.readObject());
    661                                 baseURL = (String) ois.readObject();
    662                                 images = (GeorefImage[][])ois.readObject();
    663                                 ois.close();
    664                                 fis.close();
    665                                 for (GeorefImage[] imgs : images) {
    666                                         for (GeorefImage img : imgs) {
    667                                                 if (img != null) {
    668                                                         img.setLayer(WMSLayer.this);
    669                                                 }
    670                                         }
    671                                 }
    672                                 settingsChanged = true;
    673                                 mv.repaint();
    674                                 if(baseURL != null)
    675                                 {
    676                                         startGrabberThreads();
    677                                 }
    678                         }
    679                         catch (Exception ex) {
    680                                 // FIXME be more specific
    681                                 ex.printStackTrace(System.out);
    682                                 JOptionPane.showMessageDialog(Main.parent,
    683                                                 tr("Error loading file"),
    684                                                 tr("Error"),
    685                                                 JOptionPane.ERROR_MESSAGE);
    686                                 return;
    687                         }
    688                 }
    689         }
    690         /**
    691          * This action will add a WMS layer menu entry with the current WMS layer
    692          * URL and name extended by the current resolution.
    693          * When using the menu entry again, the WMS cache will be used properly.
    694          */
    695         public class BookmarkWmsAction extends AbstractAction {
    696                 public BookmarkWmsAction() {
    697                         super(tr("Set WMS Bookmark"));
    698                 }
    699                 public void actionPerformed(ActionEvent ev) {
    700                         int i = 0;
    701                         while (Main.pref.hasKey("wmsplugin.url."+i+".url")) {
    702                                 i++;
    703                         }
    704                         String baseName;
    705                         // cut old parameter
    706                         int parameterIndex = getName().indexOf("#PPD=");
    707                         if (parameterIndex != -1) {
    708                                 baseName = getName().substring(0,parameterIndex);
    709                         }
    710                         else {
    711                                 baseName = getName();
    712                         }
    713                         Main.pref.put("wmsplugin.url."+ i +".url",baseURL );
    714                         Main.pref.put("wmsplugin.url."+String.valueOf(i)+".name",
    715                                         baseName + "#PPD=" + pixelPerDegree );
    716                         WMSPlugin.refreshMenu();
    717                 }
    718         }
    719 
    720         private class StartStopAction extends AbstractAction implements LayerAction {
    721 
    722                 public StartStopAction() {
    723                         super(tr("Automatic downloading"));
    724                 }
    725 
    726                 public Component createMenuComponent() {
    727                         JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
    728                         item.setSelected(autoDownloadEnabled);
    729                         return item;
    730                 }
    731 
    732                 public boolean supportLayers(List<Layer> layers) {
    733                         return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
    734                 }
    735 
    736                 public void actionPerformed(ActionEvent e) {
    737                         autoDownloadEnabled = !autoDownloadEnabled;
    738                         if (autoDownloadEnabled) {
    739                                 mv.repaint();
    740                         }
    741                 }
    742         }
    743 
    744         private void cancelGrabberThreads(boolean wait) {
    745                 requestQueueLock.lock();
    746                 try {
    747                         canceled = true;
    748                         for (Grabber grabber: grabbers) {
    749                                 grabber.cancel();
    750                         }
    751                         queueEmpty.signalAll();
    752                 } finally {
    753                         requestQueueLock.unlock();
    754                 }
    755                 if (wait) {
    756                         for (Thread t: grabberThreads) {
    757                                 try {
    758                                         t.join();
    759                                 } catch (InterruptedException e) {
    760                                         // Shouldn't happen
    761                                         e.printStackTrace();
    762                                 }
    763                         }
    764                 }
    765         }
    766 
    767         private void startGrabberThreads() {
    768                 int threadCount = WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.get();
    769                 requestQueueLock.lock();
    770                 try {
    771                         canceled = false;
    772                         grabbers.clear();
    773                         grabberThreads.clear();
    774                         for (int i=0; i<threadCount; i++) {
    775                                 Grabber grabber = WMSPlugin.getGrabber(mv, this);
    776                                 grabbers.add(grabber);
    777                                 Thread t = new Thread(grabber, "WMS " + getName() + " " + i);
    778                                 t.setDaemon(true);
    779                                 t.start();
    780                                 grabberThreads.add(t);
    781                         }
    782                         this.workingThreadCount = grabbers.size();
    783                         this.threadCount = grabbers.size();
    784                 } finally {
    785                         requestQueueLock.unlock();
    786                 }
    787         }
    788 
    789         @Override
    790         public boolean isChanged() {
    791                 requestQueueLock.lock();
    792                 try {
    793                         return !finishedRequests.isEmpty() || settingsChanged;
    794                 } finally {
    795                         requestQueueLock.unlock();
    796                 }
    797         }
    798 
    799         public void preferenceChanged(PreferenceChangeEvent event) {
    800                 if (event.getKey().equals(WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.getKey())) {
    801                         cancelGrabberThreads(true);
    802                         startGrabberThreads();
    803                 } else if (
    804                                 event.getKey().equals(WMSPlugin.PROP_OVERLAP.getKey())
    805                                 || event.getKey().equals(WMSPlugin.PROP_OVERLAP_EAST.getKey())
    806                                 || event.getKey().equals(WMSPlugin.PROP_OVERLAP_NORTH.getKey())) {
    807                         for (int i=0; i<images.length; i++) {
    808                                 for (int k=0; k<images[i].length; k++) {
    809                                         images[i][k] = new GeorefImage(this);
    810                                 }
    811                         }
    812 
    813                         settingsChanged = true;
    814                 }
    815         }
     56    protected static final Icon icon =
     57        new ImageIcon(Toolkit.getDefaultToolkit().createImage(WMSPlugin.class.getResource("/images/wms_small.png")));
     58
     59    public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("wmsplugin.alpha_channel", true);
     60    WMSPlugin plugin = WMSPlugin.instance;
     61
     62    public int messageNum = 5; //limit for messages per layer
     63    protected MapView mv;
     64    protected String resolution;
     65    protected int imageSize = 500;
     66    protected int dax = 10;
     67    protected int day = 10;
     68    protected int daStep = 5;
     69    protected int minZoom = 3;
     70
     71    protected double dx = 0.0;
     72    protected double dy = 0.0;
     73
     74    protected GeorefImage[][] images;
     75    protected final int serializeFormatVersion = 5;
     76    protected boolean autoDownloadEnabled = true;
     77    protected boolean settingsChanged;
     78    protected WMSInfo info;
     79
     80    // Image index boundary for current view
     81    private volatile int bminx;
     82    private volatile int bminy;
     83    private volatile int bmaxx;
     84    private volatile int bmaxy;
     85    private volatile int leftEdge;
     86    private volatile int bottomEdge;
     87
     88    // Request queue
     89    private final List<WMSRequest> requestQueue = new ArrayList<WMSRequest>();
     90    private final List<WMSRequest> finishedRequests = new ArrayList<WMSRequest>();
     91    private final Lock requestQueueLock = new ReentrantLock();
     92    private final Condition queueEmpty = requestQueueLock.newCondition();
     93    private final List<Grabber> grabbers = new ArrayList<Grabber>();
     94    private final List<Thread> grabberThreads = new ArrayList<Thread>();
     95    private int threadCount;
     96    private int workingThreadCount;
     97    private boolean canceled;
     98
     99
     100    /** set to true if this layer uses an invalid base url */
     101    private boolean usesInvalidUrl = false;
     102    /** set to true if the user confirmed to use an potentially invalid WMS base url */
     103    private boolean isInvalidUrlConfirmed = false;
     104
     105    public WMSLayer() {
     106        this(new WMSInfo(tr("Blank Layer")));
     107    }
     108
     109    public WMSLayer(WMSInfo info) {
     110        super(info.name);
     111        setBackgroundLayer(true); /* set global background variable */
     112        initializeImages();
     113        this.info = new WMSInfo(info);
     114        mv = Main.map.mapView;
     115        if(this.info.pixelPerDegree == 0.0)
     116            this.info.setPixelPerDegree(getPPD());
     117        resolution = mv.getDist100PixelText();
     118
     119        if(info.url != null) {
     120            WMSGrabber.getProjection(info.url, true);
     121            startGrabberThreads();
     122            if(!info.url.startsWith("html:") && !WMSGrabber.isUrlWithPatterns(info.url)) {
     123                if (!(info.url.endsWith("&") || info.url.endsWith("?"))) {
     124                    if (!confirmMalformedUrl(info.url)) {
     125                        System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", info.url));
     126                        usesInvalidUrl = true;
     127                        setName(getName() + tr("(deactivated)"));
     128                        return;
     129                    } else {
     130                        isInvalidUrlConfirmed = true;
     131                    }
     132                }
     133            }
     134        }
     135
     136        Main.pref.addPreferenceChangeListener(this);
     137    }
     138
     139    public void doSetName(String name) {
     140        setName(name);
     141        info.name = name;
     142    }
     143
     144    public boolean hasAutoDownload(){
     145        return autoDownloadEnabled;
     146    }
     147
     148
     149    @Override
     150    public void destroy() {
     151        cancelGrabberThreads(false);
     152        Main.pref.removePreferenceChangeListener(this);
     153    }
     154
     155    public void initializeImages() {
     156        GeorefImage[][] old = images;
     157        images = new GeorefImage[dax][day];
     158        if (old != null) {
     159            for (int i=0; i<old.length; i++) {
     160                for (int k=0; k<old[i].length; k++) {
     161                    GeorefImage o = old[i][k];
     162                    images[modulo(o.getXIndex(),dax)][modulo(o.getYIndex(),day)] = old[i][k];
     163                }
     164            }
     165        }
     166        for(int x = 0; x<dax; ++x) {
     167            for(int y = 0; y<day; ++y) {
     168                if (images[x][y] == null) {
     169                    images[x][y]= new GeorefImage(this);
     170                }
     171            }
     172        }
     173    }
     174
     175    @Override public Icon getIcon() {
     176        return icon;
     177    }
     178
     179    @Override public String getToolTipText() {
     180        if(autoDownloadEnabled)
     181            return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
     182        else
     183            return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
     184    }
     185
     186    @Override public boolean isMergable(Layer other) {
     187        return false;
     188    }
     189
     190    @Override public void mergeFrom(Layer from) {
     191    }
     192
     193    private int modulo (int a, int b) {
     194        return a % b >= 0 ? a%b : a%b+b;
     195    }
     196
     197    private boolean zoomIsTooBig() {
     198        //don't download when it's too outzoomed
     199        return info.pixelPerDegree / getPPD() > minZoom;
     200    }
     201
     202    @Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
     203        if(info.url == null || (usesInvalidUrl && !isInvalidUrlConfirmed)) return;
     204
     205        settingsChanged = false;
     206
     207        ProjectionBounds bounds = mv.getProjectionBounds();
     208        bminx= getImageXIndex(bounds.min.east());
     209        bminy= getImageYIndex(bounds.min.north());
     210        bmaxx= getImageXIndex(bounds.max.east());
     211        bmaxy= getImageYIndex(bounds.max.north());
     212
     213        leftEdge = (int)(bounds.min.east() * getPPD());
     214        bottomEdge = (int)(bounds.min.north() * getPPD());
     215
     216        if (zoomIsTooBig()) {
     217            for(int x = bminx; x<=bmaxx; ++x) {
     218                for(int y = bminy; y<=bmaxy; ++y) {
     219                    images[modulo(x,dax)][modulo(y,day)].paint(g, mv, x, y, leftEdge, bottomEdge);
     220                }
     221            }
     222        } else {
     223            downloadAndPaintVisible(g, mv, false);
     224        }
     225    }
     226
     227    protected boolean confirmMalformedUrl(String url) {
     228        if (isInvalidUrlConfirmed)
     229            return true;
     230        String msg  = tr("<html>The base URL<br>"
     231                + "''{0}''<br>"
     232                + "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
     233                + "This is likely to lead to invalid WMS request. You should check your<br>"
     234                + "preference settings.<br>"
     235                + "Do you want to fetch WMS tiles anyway?",
     236                url);
     237        String [] options = new String[] {
     238                tr("Yes, fetch images"),
     239                tr("No, abort")
     240        };
     241        int ret = JOptionPane.showOptionDialog(
     242                Main.parent,
     243                msg,
     244                tr("Invalid URL?"),
     245                JOptionPane.YES_NO_OPTION,
     246                JOptionPane.WARNING_MESSAGE,
     247                null,
     248                options, options[1]
     249        );
     250        switch(ret) {
     251        case JOptionPane.YES_OPTION: return true;
     252        default: return false;
     253        }
     254    }
     255
     256    public double getPPD(){
     257        ProjectionBounds bounds = mv.getProjectionBounds();
     258        return mv.getWidth() / (bounds.max.east() - bounds.min.east());
     259    }
     260
     261    public void displace(double dx, double dy) {
     262        settingsChanged = true;
     263        this.dx += dx;
     264        this.dy += dy;
     265    }
     266
     267    public int getImageXIndex(double coord) {
     268        return (int)Math.floor( ((coord - dx) * info.pixelPerDegree) / imageSize);
     269    }
     270
     271    public int getImageYIndex(double coord) {
     272        return (int)Math.floor( ((coord - dy) * info.pixelPerDegree) / imageSize);
     273    }
     274
     275    public int getImageX(int imageIndex) {
     276        return (int)(imageIndex * imageSize * (getPPD() / info.pixelPerDegree) + dx * getPPD());
     277    }
     278
     279    public int getImageY(int imageIndex) {
     280        return (int)(imageIndex * imageSize * (getPPD() / info.pixelPerDegree) + dy * getPPD());
     281    }
     282
     283    public int getImageWidth(int xIndex) {
     284        int overlap = (int)(plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_EAST.get() * imageSize * getPPD() / info.pixelPerDegree / 100:0);
     285        return getImageX(xIndex + 1) - getImageX(xIndex) + overlap;
     286    }
     287
     288    public int getImageHeight(int yIndex) {
     289        int overlap = (int)(plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_NORTH.get() * imageSize * getPPD() / info.pixelPerDegree / 100:0);
     290        return getImageY(yIndex + 1) - getImageY(yIndex) + overlap;
     291    }
     292
     293    /**
     294     *
     295     * @return Size of image in original zoom
     296     */
     297    public int getBaseImageWidth() {
     298        int overlap = (plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_EAST.get() * imageSize / 100:0);
     299        return imageSize + overlap;
     300    }
     301
     302    /**
     303     *
     304     * @return Size of image in original zoom
     305     */
     306    public int getBaseImageHeight() {
     307        int overlap = (plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_NORTH.get() * imageSize / 100:0);
     308        return imageSize + overlap;
     309    }
     310
     311
     312    /**
     313     *
     314     * @param xIndex
     315     * @param yIndex
     316     * @return Real EastNorth of given tile. dx/dy is not counted in
     317     */
     318    public EastNorth getEastNorth(int xIndex, int yIndex) {
     319        return new EastNorth((xIndex * imageSize) / info.pixelPerDegree, (yIndex * imageSize) / info.pixelPerDegree);
     320    }
     321
     322
     323    protected void downloadAndPaintVisible(Graphics g, final MapView mv, boolean real){
     324
     325        int newDax = dax;
     326        int newDay = day;
     327
     328        if (bmaxx - bminx >= dax || bmaxx - bminx < dax - 2 * daStep) {
     329            newDax = ((bmaxx - bminx) / daStep + 1) * daStep;
     330        }
     331
     332        if (bmaxy - bminy >= day || bmaxy - bminx < day - 2 * daStep) {
     333            newDay = ((bmaxy - bminy) / daStep + 1) * daStep;
     334        }
     335
     336        if (newDax != dax || newDay != day) {
     337            dax = newDax;
     338            day = newDay;
     339            initializeImages();
     340        }
     341
     342        for(int x = bminx; x<=bmaxx; ++x) {
     343            for(int y = bminy; y<=bmaxy; ++y){
     344                images[modulo(x,dax)][modulo(y,day)].changePosition(x, y);
     345            }
     346        }
     347
     348        gatherFinishedRequests();
     349
     350        for(int x = bminx; x<=bmaxx; ++x) {
     351            for(int y = bminy; y<=bmaxy; ++y){
     352                GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
     353                if (!img.paint(g, mv, x, y, leftEdge, bottomEdge)) {
     354                    WMSRequest request = new WMSRequest(x, y, info.pixelPerDegree, real);
     355                    addRequest(request);
     356                }
     357            }
     358        }
     359    }
     360
     361    @Override public void visitBoundingBox(BoundingXYVisitor v) {
     362        for(int x = 0; x<dax; ++x) {
     363            for(int y = 0; y<day; ++y)
     364                if(images[x][y].getImage() != null){
     365                    v.visit(images[x][y].getMin());
     366                    v.visit(images[x][y].getMax());
     367                }
     368        }
     369    }
     370
     371    @Override public Object getInfoComponent() {
     372        return getToolTipText();
     373    }
     374
     375    @Override public Action[] getMenuEntries() {
     376        return new Action[]{
     377                LayerListDialog.getInstance().createActivateLayerAction(this),
     378                LayerListDialog.getInstance().createShowHideLayerAction(),
     379                LayerListDialog.getInstance().createDeleteLayerAction(),
     380                SeparatorLayerAction.INSTANCE,
     381                new LoadWmsAction(),
     382                new SaveWmsAction(),
     383                new BookmarkWmsAction(),
     384                SeparatorLayerAction.INSTANCE,
     385                new StartStopAction(),
     386                new ToggleAlphaAction(),
     387                new ChangeResolutionAction(),
     388                new ReloadErrorTilesAction(),
     389                new DownloadAction(),
     390                SeparatorLayerAction.INSTANCE,
     391                new LayerListPopup.InfoAction(this)
     392        };
     393    }
     394
     395    public GeorefImage findImage(EastNorth eastNorth) {
     396        int xIndex = getImageXIndex(eastNorth.east());
     397        int yIndex = getImageYIndex(eastNorth.north());
     398        GeorefImage result = images[modulo(xIndex, dax)][modulo(yIndex, day)];
     399        if (result.getXIndex() == xIndex && result.getYIndex() == yIndex) {
     400            return result;
     401        } else {
     402            return null;
     403        }
     404    }
     405
     406    /**
     407     *
     408     * @param request
     409     * @return -1 if request is no longer needed, otherwise priority of request (lower number <=> more important request)
     410     */
     411    private int getRequestPriority(WMSRequest request) {
     412        if (request.getPixelPerDegree() != info.pixelPerDegree) {
     413            return -1;
     414        }
     415        if (bminx > request.getXIndex()
     416                || bmaxx < request.getXIndex()
     417                || bminy > request.getYIndex()
     418                || bmaxy < request.getYIndex()) {
     419            return -1;
     420        }
     421
     422        EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
     423        int mouseX = getImageXIndex(cursorEastNorth.east());
     424        int mouseY = getImageYIndex(cursorEastNorth.north());
     425        int dx = request.getXIndex() - mouseX;
     426        int dy = request.getYIndex() - mouseY;
     427
     428        return dx * dx + dy * dy;
     429    }
     430
     431    public WMSRequest getRequest() {
     432        requestQueueLock.lock();
     433        try {
     434            workingThreadCount--;
     435            Iterator<WMSRequest> it = requestQueue.iterator();
     436            while (it.hasNext()) {
     437                WMSRequest item = it.next();
     438                int priority = getRequestPriority(item);
     439                if (priority == -1) {
     440                    it.remove();
     441                } else {
     442                    item.setPriority(priority);
     443                }
     444            }
     445            Collections.sort(requestQueue);
     446
     447            EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
     448            int mouseX = getImageXIndex(cursorEastNorth.east());
     449            int mouseY = getImageYIndex(cursorEastNorth.north());
     450            boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY;
     451
     452            // If there is only one thread left then keep it in case we need to download other tile urgently
     453            while (!canceled &&
     454                    (requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) {
     455                try {
     456                    queueEmpty.await();
     457                } catch (InterruptedException e) {
     458                    // Shouldn't happen
     459                }
     460            }
     461
     462            workingThreadCount++;
     463            if (canceled) {
     464                return null;
     465            } else {
     466                return requestQueue.remove(0);
     467            }
     468
     469        } finally {
     470            requestQueueLock.unlock();
     471        }
     472    }
     473
     474    public void finishRequest(WMSRequest request) {
     475        if (request.getState() == null) {
     476            throw new IllegalArgumentException("Finished request without state");
     477        }
     478        requestQueueLock.lock();
     479        try {
     480            finishedRequests.add(request);
     481        } finally {
     482            requestQueueLock.unlock();
     483        }
     484    }
     485
     486    public void addRequest(WMSRequest request) {
     487        requestQueueLock.lock();
     488        try {
     489            if (!requestQueue.contains(request)) {
     490                requestQueue.add(request);
     491                queueEmpty.signalAll();
     492            }
     493        } finally {
     494            requestQueueLock.unlock();
     495        }
     496    }
     497
     498    public boolean requestIsValid(WMSRequest request) {
     499        return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex();
     500    }
     501
     502    private void gatherFinishedRequests() {
     503        requestQueueLock.lock();
     504        try {
     505            for (WMSRequest request: finishedRequests) {
     506                GeorefImage img = images[modulo(request.getXIndex(),dax)][modulo(request.getYIndex(),day)];
     507                if (img.equalPosition(request.getXIndex(), request.getYIndex())) {
     508                    img.changeImage(request.getState(), request.getImage());
     509                }
     510            }
     511        } finally {
     512            finishedRequests.clear();
     513            requestQueueLock.unlock();
     514        }
     515    }
     516
     517    public class DownloadAction extends AbstractAction {
     518        private static final long serialVersionUID = -7183852461015284020L;
     519        public DownloadAction() {
     520            super(tr("Download visible tiles"));
     521        }
     522        public void actionPerformed(ActionEvent ev) {
     523            if (zoomIsTooBig()) {
     524                JOptionPane.showMessageDialog(
     525                        Main.parent,
     526                        tr("The requested area is too big. Please zoom in a little, or change resolution"),
     527                        tr("Error"),
     528                        JOptionPane.ERROR_MESSAGE
     529                );
     530            } else {
     531                downloadAndPaintVisible(mv.getGraphics(), mv, true);
     532            }
     533        }
     534    }
     535
     536    public class ChangeResolutionAction extends AbstractAction {
     537        public ChangeResolutionAction() {
     538            super(tr("Change resolution"));
     539        }
     540        public void actionPerformed(ActionEvent ev) {
     541            initializeImages();
     542            resolution = mv.getDist100PixelText();
     543            info.setPixelPerDegree(getPPD());
     544            settingsChanged = true;
     545            mv.repaint();
     546        }
     547    }
     548
     549    public class ReloadErrorTilesAction extends AbstractAction {
     550        public ReloadErrorTilesAction() {
     551            super(tr("Reload erroneous tiles"));
     552        }
     553        public void actionPerformed(ActionEvent ev) {
     554            // Delete small files, because they're probably blank tiles.
     555            // See https://josm.openstreetmap.de/ticket/2307
     556            plugin.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
     557
     558            for (int x = 0; x < dax; ++x) {
     559                for (int y = 0; y < day; ++y) {
     560                    GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
     561                    if(img.getState() == State.FAILED){
     562                        addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), info.pixelPerDegree, true));
     563                        mv.repaint();
     564                    }
     565                }
     566            }
     567        }
     568    }
     569
     570    public class ToggleAlphaAction extends AbstractAction implements LayerAction {
     571        public ToggleAlphaAction() {
     572            super(tr("Alpha channel"));
     573        }
     574        public void actionPerformed(ActionEvent ev) {
     575            JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
     576            boolean alphaChannel = checkbox.isSelected();
     577            PROP_ALPHA_CHANNEL.put(alphaChannel);
     578
     579            // clear all resized cached instances and repaint the layer
     580            for (int x = 0; x < dax; ++x) {
     581                for (int y = 0; y < day; ++y) {
     582                    GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
     583                    img.flushedResizedCachedInstance();
     584                }
     585            }
     586            mv.repaint();
     587        }
     588        public Component createMenuComponent() {
     589            JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
     590            item.setSelected(PROP_ALPHA_CHANNEL.get());
     591            return item;
     592        }
     593        public boolean supportLayers(List<Layer> layers) {
     594            return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
     595        }
     596    }
     597
     598    public class SaveWmsAction extends AbstractAction {
     599        public SaveWmsAction() {
     600            super(tr("Save WMS layer to file"), ImageProvider.get("save"));
     601        }
     602        public void actionPerformed(ActionEvent ev) {
     603            File f = SaveActionBase.createAndOpenSaveFileChooser(
     604                    tr("Save WMS layer"), ".wms");
     605            try {
     606                if (f != null) {
     607                    ObjectOutputStream oos = new ObjectOutputStream(
     608                            new FileOutputStream(f)
     609                    );
     610                    oos.writeInt(serializeFormatVersion);
     611                    oos.writeInt(dax);
     612                    oos.writeInt(day);
     613                    oos.writeInt(imageSize);
     614                    oos.writeDouble(info.pixelPerDegree);
     615                    oos.writeObject(info.name);
     616                    oos.writeObject(info.getFullURL());
     617                    oos.writeObject(images);
     618                    oos.close();
     619                }
     620            } catch (Exception ex) {
     621                ex.printStackTrace(System.out);
     622            }
     623        }
     624    }
     625
     626    public class LoadWmsAction extends AbstractAction {
     627        public LoadWmsAction() {
     628            super(tr("Load WMS layer from file"), ImageProvider.get("load"));
     629        }
     630        public void actionPerformed(ActionEvent ev) {
     631            JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
     632                    false, tr("Load WMS layer"), "wms");
     633            if(fc == null) return;
     634            File f = fc.getSelectedFile();
     635            if (f == null) return;
     636            try
     637            {
     638                FileInputStream fis = new FileInputStream(f);
     639                ObjectInputStream ois = new ObjectInputStream(fis);
     640                int sfv = ois.readInt();
     641                if (sfv != serializeFormatVersion) {
     642                    JOptionPane.showMessageDialog(Main.parent,
     643                            tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
     644                            tr("File Format Error"),
     645                            JOptionPane.ERROR_MESSAGE);
     646                    return;
     647                }
     648                autoDownloadEnabled = false;
     649                dax = ois.readInt();
     650                day = ois.readInt();
     651                imageSize = ois.readInt();
     652                info.setPixelPerDegree(ois.readDouble());
     653                doSetName((String)ois.readObject());
     654                info.setURL((String) ois.readObject());
     655                images = (GeorefImage[][])ois.readObject();
     656                ois.close();
     657                fis.close();
     658                for (GeorefImage[] imgs : images) {
     659                    for (GeorefImage img : imgs) {
     660                        if (img != null) {
     661                            img.setLayer(WMSLayer.this);
     662                        }
     663                    }
     664                }
     665                settingsChanged = true;
     666                mv.repaint();
     667                if(info.url != null)
     668                {
     669                    startGrabberThreads();
     670                }
     671            }
     672            catch (Exception ex) {
     673                // FIXME be more specific
     674                ex.printStackTrace(System.out);
     675                JOptionPane.showMessageDialog(Main.parent,
     676                        tr("Error loading file"),
     677                        tr("Error"),
     678                        JOptionPane.ERROR_MESSAGE);
     679                return;
     680            }
     681        }
     682    }
     683    /**
     684     * This action will add a WMS layer menu entry with the current WMS layer
     685     * URL and name extended by the current resolution.
     686     * When using the menu entry again, the WMS cache will be used properly.
     687     */
     688    public class BookmarkWmsAction extends AbstractAction {
     689        public BookmarkWmsAction() {
     690            super(tr("Set WMS Bookmark"));
     691        }
     692        public void actionPerformed(ActionEvent ev) {
     693            plugin.addLayer(new WMSInfo(info));
     694        }
     695    }
     696
     697    private class StartStopAction extends AbstractAction implements LayerAction {
     698
     699        public StartStopAction() {
     700            super(tr("Automatic downloading"));
     701        }
     702
     703        public Component createMenuComponent() {
     704            JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
     705            item.setSelected(autoDownloadEnabled);
     706            return item;
     707        }
     708
     709        public boolean supportLayers(List<Layer> layers) {
     710            return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
     711        }
     712
     713        public void actionPerformed(ActionEvent e) {
     714            autoDownloadEnabled = !autoDownloadEnabled;
     715            if (autoDownloadEnabled) {
     716                mv.repaint();
     717            }
     718        }
     719    }
     720
     721    private void cancelGrabberThreads(boolean wait) {
     722        requestQueueLock.lock();
     723        try {
     724            canceled = true;
     725            for (Grabber grabber: grabbers) {
     726                grabber.cancel();
     727            }
     728            queueEmpty.signalAll();
     729        } finally {
     730            requestQueueLock.unlock();
     731        }
     732        if (wait) {
     733            for (Thread t: grabberThreads) {
     734                try {
     735                    t.join();
     736                } catch (InterruptedException e) {
     737                    // Shouldn't happen
     738                    e.printStackTrace();
     739                }
     740            }
     741        }
     742    }
     743
     744    private void startGrabberThreads() {
     745        int threadCount = plugin.PROP_SIMULTANEOUS_CONNECTIONS.get();
     746        requestQueueLock.lock();
     747        try {
     748            canceled = false;
     749            grabbers.clear();
     750            grabberThreads.clear();
     751            for (int i=0; i<threadCount; i++) {
     752                Grabber grabber = plugin.getGrabber(mv, this);
     753                grabbers.add(grabber);
     754                Thread t = new Thread(grabber, "WMS " + getName() + " " + i);
     755                t.setDaemon(true);
     756                t.start();
     757                grabberThreads.add(t);
     758            }
     759            this.workingThreadCount = grabbers.size();
     760            this.threadCount = grabbers.size();
     761        } finally {
     762            requestQueueLock.unlock();
     763        }
     764    }
     765
     766    @Override
     767    public boolean isChanged() {
     768        requestQueueLock.lock();
     769        try {
     770            return !finishedRequests.isEmpty() || settingsChanged;
     771        } finally {
     772            requestQueueLock.unlock();
     773        }
     774    }
     775
     776    public void preferenceChanged(PreferenceChangeEvent event) {
     777        if (event.getKey().equals(plugin.PROP_SIMULTANEOUS_CONNECTIONS.getKey())) {
     778            cancelGrabberThreads(true);
     779            startGrabberThreads();
     780        } else if (
     781                event.getKey().equals(plugin.PROP_OVERLAP.getKey())
     782                || event.getKey().equals(plugin.PROP_OVERLAP_EAST.getKey())
     783                || event.getKey().equals(plugin.PROP_OVERLAP_NORTH.getKey())) {
     784            for (int i=0; i<images.length; i++) {
     785                for (int k=0; k<images[i].length; k++) {
     786                    images[i][k] = new GeorefImage(this);
     787                }
     788            }
     789
     790            settingsChanged = true;
     791        }
     792    }
    816793
    817794}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSPlugin.java

    r22960 r23207  
    77import java.awt.event.ActionEvent;
    88import java.awt.event.KeyEvent;
    9 import java.io.BufferedReader;
    109import java.io.File;
    11 import java.io.FileNotFoundException;
    12 import java.io.FileOutputStream;
    13 import java.io.IOException;
    14 import java.io.InputStream;
    15 import java.io.InputStreamReader;
    16 import java.io.UnsupportedEncodingException;
    1710import java.lang.reflect.InvocationTargetException;
    1811import java.lang.reflect.Method;
    19 import java.util.ArrayList;
    20 import java.util.Collections;
    21 import java.util.Map;
    22 import java.util.TreeMap;
    23 import java.util.TreeSet;
    2412
    2513import javax.swing.JMenu;
     
    3826import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
    3927import org.openstreetmap.josm.io.CacheFiles;
    40 import org.openstreetmap.josm.io.MirroredInputStream;
    4128import org.openstreetmap.josm.plugins.Plugin;
    4229import org.openstreetmap.josm.plugins.PluginHandler;
     
    4835
    4936public class WMSPlugin extends Plugin {
    50         static CacheFiles cache = new CacheFiles("wmsplugin");
    51 
    52         public static final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("wmsplugin.simultaneousConnections", 3);
    53         public static final BooleanProperty PROP_OVERLAP = new BooleanProperty("wmsplugin.url.overlap", false);
    54         public static final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("wmsplugin.url.overlapEast", 14);
    55         public static final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("wmsplugin.url.overlapNorth", 4);
    56 
    57         WMSLayer wmsLayer;
    58         static JMenu wmsJMenu;
    59 
    60         static ArrayList<WMSInfo> wmsList = new ArrayList<WMSInfo>();
    61         static TreeMap<String,String> wmsListDefault = new TreeMap<String,String>();
    62 
    63         // remember state of menu item to restore on changed preferences
    64         static private boolean menuEnabled = false;
    65 
    66         /***************************************************************
    67          * Remote control initialization:
    68          * If you need remote control in some other plug-in
    69          * copy this stuff and the call to initRemoteControl below
    70          * and replace the RequestHandler subclass in initRemoteControl
    71          ***************************************************************/
    72 
    73         /** name of remote control plugin */
    74         private static final String REMOTECONTROL_NAME = "remotecontrol";
    75 
    76         /* if necessary change these version numbers to ensure compatibility */
    77 
    78         /** RemoteControlPlugin older than this SVN revision is not compatible */
    79         static final int REMOTECONTROL_MIN_REVISION = 22734;
    80         /** WMSPlugin needs this specific API major version of RemoteControlPlugin */
    81         static final int REMOTECONTROL_NEED_API_MAJOR = 1;
    82         /** All API minor versions starting from this should be compatible */
    83         static final int REMOTECONTROL_MIN_API_MINOR = 0;
    84 
    85         /* these fields will contain state and version of remote control plug-in */
    86         boolean remoteControlAvailable = false;
    87         boolean remoteControlCompatible = true;
    88         boolean remoteControlInitialized = false;
    89         int remoteControlRevision = 0;
    90         int remoteControlApiMajor = 0;
    91         int remoteControlApiMinor = 0;
    92         int remoteControlProtocolMajor = 0;
    93         int remoteControlProtocolMinor = 0;
    94 
    95         /**
    96          * Check if remote control plug-in is available and if its version is
    97          * high enough and register remote control command for this plug-in.
    98          */
    99         private void initRemoteControl() {
    100                 for(PluginProxy pp: PluginHandler.pluginList)
    101                 {
    102                         PluginInformation info = pp.getPluginInformation();
    103                         if(REMOTECONTROL_NAME.equals(info.name))
    104                         {
    105                                 remoteControlAvailable = true;
    106                                 remoteControlRevision = Integer.parseInt(info.version);
    107                                 if(REMOTECONTROL_MIN_REVISION > remoteControlRevision)
    108                                 {
    109                                         remoteControlCompatible = false;
    110                                 }
    111                         }
    112                 }
    113 
    114                 if(remoteControlAvailable && remoteControlCompatible)
    115                 {
    116                         Plugin plugin =
    117                                 (Plugin) PluginHandler.getPlugin(REMOTECONTROL_NAME);
    118                         try {
    119                                 Method method;
    120                                 method = plugin.getClass().getMethod("getVersion");
    121                                 Object obj = method.invoke(plugin);
    122                                 if((obj != null ) && (obj instanceof int[]))
    123                                 {
    124                                         int[] versions = (int[]) obj;
    125                                         if(versions.length >= 4)
    126                                         {
    127                                                 remoteControlApiMajor = versions[0];
    128                                                 remoteControlApiMinor = versions[1];
    129                                                 remoteControlProtocolMajor = versions[2];
    130                                                 remoteControlProtocolMinor = versions[3];
    131                                         }
    132                                 }
    133 
    134                                 if((remoteControlApiMajor != REMOTECONTROL_NEED_API_MAJOR) ||
    135                                                 (remoteControlApiMinor < REMOTECONTROL_MIN_API_MINOR))
    136                                 {
    137                                         remoteControlCompatible = false;
    138                                 }
    139                                 if(remoteControlCompatible)
    140                                 {
    141                                         System.out.println(this.getClass().getSimpleName() + ": initializing remote control");
    142                                         method = plugin.getClass().getMethod("addRequestHandler", String.class, Class.class);
    143                                         // replace command and class when you copy this to some other plug-in
    144                                         // for compatibility with old remotecontrol add leading "/"
    145                                         method.invoke(plugin, "/" + WMSRemoteHandler.command, WMSRemoteHandler.class);
    146                                         remoteControlInitialized = true;
    147                                 }
    148                         } catch (SecurityException e) {
    149                                 e.printStackTrace();
    150                         } catch (NoSuchMethodException e) {
    151                                 e.printStackTrace();
    152                         } catch (IllegalArgumentException e) {
    153                                 e.printStackTrace();
    154                         } catch (IllegalAccessException e) {
    155                                 e.printStackTrace();
    156                         } catch (InvocationTargetException e) {
    157                                 e.printStackTrace();
    158                         }
    159                 }
    160                 if(remoteControlAvailable)
    161                 {
    162                         String msg = null;
    163 
    164                         if(remoteControlCompatible)
    165                         {
    166                                 if(!remoteControlInitialized)
    167                                 {
    168                                         msg  = tr("Could not initialize remote control.");
    169                                 }
    170                         }
    171                         else
    172                         {
    173                                 msg  = tr("Remote control plugin is not compatible with {0}.",
    174                                                 this.getClass().getSimpleName());
    175                         }
    176 
    177                         if(msg != null)
    178                         {
    179                                 String additionalMessage = tr("{0} will work but remote control for this plugin is disabled.\n"
    180                                                 + "You should update the plugins.",
    181                                                 this.getClass().getSimpleName());
    182                                 String versionMessage = tr("Current version of \"{1}\": {2}, internal version {3}. "
    183                                                 + "Need version {4}, internal version {5}.\n"
    184                                                 + "If updating the plugins does not help report a bug for \"{0}\".",
    185                                                 this.getClass().getSimpleName(),
    186                                                 REMOTECONTROL_NAME,
    187                                                 ""+remoteControlRevision,
    188                                                 (remoteControlApiMajor != 0) ?
    189                                                                 ""+remoteControlApiMajor+"."+remoteControlApiMinor :
    190                                                                         tr("unknown"),
    191                                                                         ""+REMOTECONTROL_MIN_REVISION,
    192                                                                         ""+REMOTECONTROL_NEED_API_MAJOR+"."+REMOTECONTROL_MIN_API_MINOR );
    193 
    194                                 String title = tr("{0}: Problem with remote control",
    195                                                 this.getClass().getSimpleName());
    196 
    197                                 System.out.println(this.getClass().getSimpleName() + ": " +
    198                                                 msg + "\n" + versionMessage);
    199 
    200                                 JOptionPane.showMessageDialog(
    201                                                 Main.parent,
    202                                                 msg + "\n" + additionalMessage,
    203                                                 title,
    204                                                 JOptionPane.WARNING_MESSAGE
    205                                 );
    206                         }
    207                 }
    208 
    209                 if(!remoteControlAvailable) {
    210                         System.out.println(this.getClass().getSimpleName() + ": remote control not available");
    211                 }
    212         }
    213 
    214         /***************************************
    215          * end of remote control initialization
    216          ***************************************/
    217 
    218         protected void initExporterAndImporter() {
    219                 ExtensionFileFilter.exporters.add(new WMSLayerExporter());
    220                 ExtensionFileFilter.importers.add(new WMSLayerImporter());
    221         }
    222 
    223         public WMSPlugin(PluginInformation info) {
    224                 super(info);
    225                 /*
    226                 System.out.println("constructor " + this.getClass().getName() + " (" + info.name +
    227                                 " v " + info.version + " stage " + info.stage + ")");
    228                  */
    229                 refreshMenu();
    230                 cache.setExpire(CacheFiles.EXPIRE_MONTHLY, false);
    231                 cache.setMaxSize(70, false);
    232                 initExporterAndImporter();
    233                 initRemoteControl();
    234         }
    235 
    236         // this parses the preferences settings. preferences for the wms plugin have to
    237         // look like this:
    238         // wmsplugin.1.name=Landsat
    239         // wmsplugin.1.url=http://and.so.on/
    240 
    241         @Override
    242         public void copy(String from, String to) throws FileNotFoundException, IOException
    243         {
    244                 File pluginDir = new File(getPrefsPath());
    245                 if (!pluginDir.exists())
    246                         pluginDir.mkdirs();
    247                 FileOutputStream out = new FileOutputStream(getPrefsPath() + to);
    248                 InputStream in = WMSPlugin.class.getResourceAsStream(from);
    249                 byte[] buffer = new byte[8192];
    250                 for(int len = in.read(buffer); len > 0; len = in.read(buffer))
    251                         out.write(buffer, 0, len);
    252                 in.close();
    253                 out.close();
    254         }
    255 
    256 
    257         public static void refreshMenu() {
    258                 wmsList.clear();
    259                 Map<String,String> prefs = Main.pref.getAllPrefix("wmsplugin.url.");
    260 
    261                 TreeSet<String> keys = new TreeSet<String>(prefs.keySet());
    262 
    263                 // And then the names+urls of WMS servers
    264                 int prefid = 0;
    265                 String name = null;
    266                 String url = null;
    267                 String cookies = "";
    268                 int lastid = -1;
    269                 for (String key : keys) {
    270                         String[] elements = key.split("\\.");
    271                         if (elements.length != 4) continue;
    272                         try {
    273                                 prefid = Integer.parseInt(elements[2]);
    274                         } catch(NumberFormatException e) {
    275                                 continue;
    276                         }
    277                         if (prefid != lastid) {
    278                                 name = url = null; lastid = prefid;
    279                         }
    280                         if (elements[3].equals("name"))
    281                                 name = prefs.get(key);
    282                         else if (elements[3].equals("url"))
    283                         {
    284                                 /* FIXME: Remove the if clause after some time */
    285                                 if(!prefs.get(key).startsWith("yahoo:")) /* legacy stuff */
    286                                         url = prefs.get(key);
    287                         }
    288                         else if (elements[3].equals("cookies"))
    289                                 cookies = prefs.get(key);
    290                         if (name != null && url != null)
    291                                 wmsList.add(new WMSInfo(name, url, cookies, prefid));
    292                 }
    293                 String source = "http://svn.openstreetmap.org/applications/editors/josm/plugins/wmsplugin/sources.cfg";
    294                 try
    295                 {
    296                         MirroredInputStream s = new MirroredInputStream(source,
    297                                         Main.pref.getPreferencesDir() + "plugins/wmsplugin/", -1);
    298                         InputStreamReader r;
    299                         try
    300                         {
    301                                 r = new InputStreamReader(s, "UTF-8");
    302                         }
    303                         catch (UnsupportedEncodingException e)
    304                         {
    305                                 r = new InputStreamReader(s);
    306                         }
    307                         BufferedReader reader = new BufferedReader(r);
    308                         String line;
    309                         while((line = reader.readLine()) != null)
    310                         {
    311                                 String val[] = line.split(";");
    312                                 if(!line.startsWith("#") && val.length == 3)
    313                                         setDefault("true".equals(val[0]), tr(val[1]), val[2]);
    314                         }
    315                 }
    316                 catch (IOException e)
    317                 {
    318                 }
    319 
    320                 Collections.sort(wmsList);
    321                 MainMenu menu = Main.main.menu;
    322 
    323                 if (wmsJMenu == null)
    324                         wmsJMenu = menu.addMenu(marktr("WMS"), KeyEvent.VK_W, menu.defaultMenuPos, ht("/Plugin/WMS"));
    325                 else
    326                         wmsJMenu.removeAll();
    327 
    328                 // for each configured WMSInfo, add a menu entry.
    329                 for (final WMSInfo u : wmsList) {
    330                         wmsJMenu.add(new JMenuItem(new WMSDownloadAction(u)));
    331                 }
    332                 wmsJMenu.addSeparator();
    333                 wmsJMenu.add(new JMenuItem(new Map_Rectifier_WMSmenuAction()));
    334 
    335                 wmsJMenu.addSeparator();
    336                 wmsJMenu.add(new JMenuItem(new
    337                                 JosmAction(tr("Blank Layer"), "blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
    338                         public void actionPerformed(ActionEvent ev) {
    339                                 Main.main.addLayer(new WMSLayer());
    340                         }
    341                 }));
    342                 setEnabledAll(menuEnabled);
    343         }
    344 
    345         /* add a default entry in case the URL does not yet exist */
    346         private static void setDefault(Boolean force, String name, String url)
    347         {
    348                 String testurl = url.replaceAll("=", "_");
    349                 wmsListDefault.put(name, url);
    350 
    351                 if(force && !Main.pref.getBoolean("wmsplugin.default."+testurl))
    352                 {
    353                         Main.pref.put("wmsplugin.default."+testurl, true);
    354                         int id = -1;
    355                         for(WMSInfo i : wmsList)
    356                         {
    357                                 if(url.equals(i.url))
    358                                         return;
    359                                 if(i.prefid > id)
    360                                         id = i.prefid;
    361                         }
    362                         WMSInfo newinfo = new WMSInfo(name, url, id+1);
    363                         newinfo.save();
    364                         wmsList.add(newinfo);
    365                 }
    366         }
    367 
    368         public static Grabber getGrabber(MapView mv, WMSLayer layer){
    369                 if(layer.baseURL.startsWith("html:"))
    370                         return new HTMLGrabber(mv, layer, cache);
    371                 else
    372                         return new WMSGrabber(mv, layer, cache);
    373         }
    374 
    375         private static void setEnabledAll(boolean isEnabled) {
    376                 for(int i=0; i < wmsJMenu.getItemCount(); i++) {
    377                         JMenuItem item = wmsJMenu.getItem(i);
    378 
    379                         if(item != null) item.setEnabled(isEnabled);
    380                 }
    381                 menuEnabled = isEnabled;
    382         }
    383 
    384         @Override
    385         public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
    386                 if (oldFrame==null && newFrame!=null) {
    387                         setEnabledAll(true);
    388                         Main.map.addMapMode(new IconToggleButton
    389                                         (new WMSAdjustAction(Main.map)));
    390                 } else if (oldFrame!=null && newFrame==null ) {
    391                         setEnabledAll(false);
    392                 }
    393         }
    394 
    395         @Override
    396         public PreferenceSetting getPreferenceSetting() {
    397                 return new WMSPreferenceEditor();
    398         }
    399 
    400         static public String getPrefsPath()
    401         {
    402                 return Main.pref.getPluginsDirectory().getPath() + "/wmsplugin/";
    403         }
     37    CacheFiles cache = new CacheFiles("wmsplugin");
     38
     39    public final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("wmsplugin.simultaneousConnections", 3);
     40    public final BooleanProperty PROP_OVERLAP = new BooleanProperty("wmsplugin.url.overlap", false);
     41    public final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("wmsplugin.url.overlapEast", 14);
     42    public final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("wmsplugin.url.overlapNorth", 4);
     43
     44    JMenu wmsJMenu;
     45    static WMSPlugin instance;
     46
     47    public WMSLayerInfo info = new WMSLayerInfo();
     48
     49    // remember state of menu item to restore on changed preferences
     50    private boolean menuEnabled = false;
     51
     52    /***************************************************************
     53     * Remote control initialization:
     54     * If you need remote control in some other plug-in
     55     * copy this stuff and the call to initRemoteControl below
     56     * and replace the RequestHandler subclass in initRemoteControl
     57     ***************************************************************/
     58
     59    /** name of remote control plugin */
     60    private final String REMOTECONTROL_NAME = "remotecontrol";
     61
     62    /* if necessary change these version numbers to ensure compatibility */
     63
     64    /** RemoteControlPlugin older than this SVN revision is not compatible */
     65    final int REMOTECONTROL_MIN_REVISION = 22734;
     66    /** WMSPlugin needs this specific API major version of RemoteControlPlugin */
     67    final int REMOTECONTROL_NEED_API_MAJOR = 1;
     68    /** All API minor versions starting from this should be compatible */
     69    final int REMOTECONTROL_MIN_API_MINOR = 0;
     70
     71    /* these fields will contain state and version of remote control plug-in */
     72    boolean remoteControlAvailable = false;
     73    boolean remoteControlCompatible = true;
     74    boolean remoteControlInitialized = false;
     75    int remoteControlRevision = 0;
     76    int remoteControlApiMajor = 0;
     77    int remoteControlApiMinor = 0;
     78    int remoteControlProtocolMajor = 0;
     79    int remoteControlProtocolMinor = 0;
     80
     81    /**
     82     * Check if remote control plug-in is available and if its version is
     83     * high enough and register remote control command for this plug-in.
     84     */
     85    private void initRemoteControl() {
     86        for(PluginProxy pp: PluginHandler.pluginList)
     87        {
     88            PluginInformation info = pp.getPluginInformation();
     89            if(REMOTECONTROL_NAME.equals(info.name))
     90            {
     91                remoteControlAvailable = true;
     92                remoteControlRevision = Integer.parseInt(info.version);
     93                if(REMOTECONTROL_MIN_REVISION > remoteControlRevision)
     94                {
     95                    remoteControlCompatible = false;
     96                }
     97            }
     98        }
     99
     100        if(remoteControlAvailable && remoteControlCompatible)
     101        {
     102            Plugin plugin =
     103                (Plugin) PluginHandler.getPlugin(REMOTECONTROL_NAME);
     104            try {
     105                Method method;
     106                method = plugin.getClass().getMethod("getVersion");
     107                Object obj = method.invoke(plugin);
     108                if((obj != null ) && (obj instanceof int[]))
     109                {
     110                    int[] versions = (int[]) obj;
     111                    if(versions.length >= 4)
     112                    {
     113                        remoteControlApiMajor = versions[0];
     114                        remoteControlApiMinor = versions[1];
     115                        remoteControlProtocolMajor = versions[2];
     116                        remoteControlProtocolMinor = versions[3];
     117                    }
     118                }
     119
     120                if((remoteControlApiMajor != REMOTECONTROL_NEED_API_MAJOR) ||
     121                        (remoteControlApiMinor < REMOTECONTROL_MIN_API_MINOR))
     122                {
     123                    remoteControlCompatible = false;
     124                }
     125                if(remoteControlCompatible)
     126                {
     127                    System.out.println(this.getClass().getSimpleName() + ": initializing remote control");
     128                    method = plugin.getClass().getMethod("addRequestHandler", String.class, Class.class);
     129                    // replace command and class when you copy this to some other plug-in
     130                    // for compatibility with old remotecontrol add leading "/"
     131                    method.invoke(plugin, "/" + WMSRemoteHandler.command, WMSRemoteHandler.class);
     132                    remoteControlInitialized = true;
     133                }
     134            } catch (SecurityException e) {
     135                e.printStackTrace();
     136            } catch (NoSuchMethodException e) {
     137                e.printStackTrace();
     138            } catch (IllegalArgumentException e) {
     139                e.printStackTrace();
     140            } catch (IllegalAccessException e) {
     141                e.printStackTrace();
     142            } catch (InvocationTargetException e) {
     143                e.printStackTrace();
     144            }
     145        }
     146        if(remoteControlAvailable)
     147        {
     148            String msg = null;
     149
     150            if(remoteControlCompatible)
     151            {
     152                if(!remoteControlInitialized)
     153                {
     154                    msg  = tr("Could not initialize remote control.");
     155                }
     156            }
     157            else
     158            {
     159                msg  = tr("Remote control plugin is not compatible with {0}.",
     160                        this.getClass().getSimpleName());
     161            }
     162
     163            if(msg != null)
     164            {
     165                String additionalMessage = tr("{0} will work but remote control for this plugin is disabled.\n"
     166                        + "You should update the plugins.",
     167                        this.getClass().getSimpleName());
     168                String versionMessage = tr("Current version of \"{1}\": {2}, internal version {3}. "
     169                        + "Need version {4}, internal version {5}.\n"
     170                        + "If updating the plugins does not help report a bug for \"{0}\".",
     171                        this.getClass().getSimpleName(),
     172                        REMOTECONTROL_NAME,
     173                        ""+remoteControlRevision,
     174                        (remoteControlApiMajor != 0) ?
     175                                ""+remoteControlApiMajor+"."+remoteControlApiMinor :
     176                                    tr("unknown"),
     177                                    ""+REMOTECONTROL_MIN_REVISION,
     178                                    ""+REMOTECONTROL_NEED_API_MAJOR+"."+REMOTECONTROL_MIN_API_MINOR );
     179
     180                String title = tr("{0}: Problem with remote control",
     181                        this.getClass().getSimpleName());
     182
     183                System.out.println(this.getClass().getSimpleName() + ": " +
     184                        msg + "\n" + versionMessage);
     185
     186                JOptionPane.showMessageDialog(
     187                        Main.parent,
     188                        msg + "\n" + additionalMessage,
     189                        title,
     190                        JOptionPane.WARNING_MESSAGE
     191                );
     192            }
     193        }
     194
     195        if(!remoteControlAvailable) {
     196            System.out.println(this.getClass().getSimpleName() + ": remote control not available");
     197        }
     198    }
     199
     200    /***************************************
     201     * end of remote control initialization
     202     ***************************************/
     203
     204    protected void initExporterAndImporter() {
     205        ExtensionFileFilter.exporters.add(new WMSLayerExporter());
     206        ExtensionFileFilter.importers.add(new WMSLayerImporter());
     207    }
     208
     209    public WMSPlugin(PluginInformation info) {
     210        super(info);
     211        instance = this;
     212        this.info.load();
     213        refreshMenu();
     214        cache.setExpire(CacheFiles.EXPIRE_MONTHLY, false);
     215        cache.setMaxSize(70, false);
     216        initExporterAndImporter();
     217        initRemoteControl();
     218    }
     219
     220    public void addLayer(WMSInfo info) {
     221        this.info.add(info);
     222        this.info.save();
     223        refreshMenu();
     224    }
     225
     226    public void refreshMenu() {
     227        MainMenu menu = Main.main.menu;
     228
     229        if (wmsJMenu == null)
     230            wmsJMenu = menu.addMenu(marktr("WMS"), KeyEvent.VK_W, menu.defaultMenuPos, ht("/Plugin/WMS"));
     231        else
     232            wmsJMenu.removeAll();
     233
     234        // for each configured WMSInfo, add a menu entry.
     235        for (final WMSInfo u : info.layers) {
     236            wmsJMenu.add(new JMenuItem(new WMSDownloadAction(u)));
     237        }
     238        wmsJMenu.addSeparator();
     239        wmsJMenu.add(new JMenuItem(new Map_Rectifier_WMSmenuAction()));
     240
     241        wmsJMenu.addSeparator();
     242        wmsJMenu.add(new JMenuItem(new
     243                JosmAction(tr("Blank Layer"), "blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
     244            public void actionPerformed(ActionEvent ev) {
     245                Main.main.addLayer(new WMSLayer());
     246            }
     247        }));
     248        setEnabledAll(menuEnabled);
     249    }
     250
     251    public Grabber getGrabber(MapView mv, WMSLayer layer){
     252        if(layer.info.html)
     253            return new HTMLGrabber(mv, layer, cache);
     254        else
     255            return new WMSGrabber(mv, layer, cache);
     256    }
     257
     258    private void setEnabledAll(boolean isEnabled) {
     259        for(int i=0; i < wmsJMenu.getItemCount(); i++) {
     260            JMenuItem item = wmsJMenu.getItem(i);
     261
     262            if(item != null) item.setEnabled(isEnabled);
     263        }
     264        menuEnabled = isEnabled;
     265    }
     266
     267    @Override
     268    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
     269        if (oldFrame==null && newFrame!=null) {
     270            setEnabledAll(true);
     271            Main.map.addMapMode(new IconToggleButton
     272                    (new WMSAdjustAction(Main.map)));
     273        } else if (oldFrame!=null && newFrame==null ) {
     274            setEnabledAll(false);
     275        }
     276    }
     277
     278    @Override
     279    public PreferenceSetting getPreferenceSetting() {
     280        return new WMSPreferenceEditor();
     281    }
     282
     283    @Override
     284    public String getPluginDir()
     285    {
     286        return new File(Main.pref.getPluginsDirectory(), "wmsplugin").getPath();
     287    }
    404288}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java

    r22936 r23207  
    22
    33import static org.openstreetmap.josm.tools.I18n.tr;
     4import static org.openstreetmap.josm.tools.I18n.trc;
    45
    56import java.awt.Dimension;
     
    89import java.awt.event.ActionEvent;
    910import java.awt.event.ActionListener;
     11import java.awt.event.MouseEvent;
     12import java.util.ArrayList;
    1013import java.util.HashMap;
    1114import java.util.Map;
     
    2326import javax.swing.SpinnerNumberModel;
    2427import javax.swing.table.DefaultTableModel;
     28import javax.swing.table.TableColumnModel;
    2529
    2630import org.openstreetmap.josm.Main;
     
    3034
    3135public class WMSPreferenceEditor implements PreferenceSetting {
    32     private DefaultTableModel model;
     36    private WMSLayerTableModel model;
    3337    private JComboBox browser;
    34     private HashMap<Integer, WMSInfo> oldValues = new HashMap<Integer, WMSInfo>();
    3538
    3639    JCheckBox overlapCheckBox;
     
    4043    JCheckBox remoteCheckBox;
    4144    boolean allowRemoteControl = true;
     45    WMSPlugin plugin = WMSPlugin.instance;
    4246
    4347    public void addGui(final PreferenceTabbedPane gui) {
    4448        JPanel p = gui.createPreferenceTab("wms", tr("WMS Plugin Preferences"), tr("Modify list of WMS servers displayed in the WMS plugin menu"));
    4549
    46         model = new DefaultTableModel(new String[]{tr("Menu Name"), tr("WMS URL")}, 0);
    47         final JTable list = new JTable(model);
     50        model = new WMSLayerTableModel();
     51        final JTable list = new JTable(model) {
     52            @Override
     53            public String getToolTipText(MouseEvent e) {
     54                java.awt.Point p = e.getPoint();
     55                return (String) model.getValueAt(rowAtPoint(p), columnAtPoint(p));
     56            }
     57        };
    4858        JScrollPane scroll = new JScrollPane(list);
    4959        p.add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
    5060        scroll.setPreferredSize(new Dimension(200,200));
    5161
    52         for (WMSInfo i : WMSPlugin.wmsList) {
    53             oldValues.put(i.prefid, i);
    54             model.addRow(new String[]{i.name, i.url});
    55         }
    56 
    57         final DefaultTableModel modeldef = new DefaultTableModel(
    58                 new String[]{tr("Menu Name (Default)"), tr("WMS URL (Default)")}, 0);
    59         final JTable listdef = new JTable(modeldef){
     62        final WMSDefaultLayerTableModel modeldef = new WMSDefaultLayerTableModel();
     63        final JTable listdef = new JTable(modeldef) {
    6064            @Override
    61             public boolean isCellEditable(int row,int column){return false;}
     65            public String getToolTipText(MouseEvent e) {
     66                java.awt.Point p = e.getPoint();
     67                return (String) modeldef.getValueAt(rowAtPoint(p), columnAtPoint(p));
     68            }
    6269        };
    6370        JScrollPane scrolldef = new JScrollPane(listdef);
     
    6673        scrolldef.setPreferredSize(new Dimension(200,200));
    6774
    68         for (Map.Entry<String,String> i : WMSPlugin.wmsListDefault.entrySet()) {
    69             modeldef.addRow(new String[]{i.getKey(), i.getValue()});
    70         }
     75        TableColumnModel mod = listdef.getColumnModel();
     76        mod.getColumn(1).setPreferredWidth(800);
     77        mod.getColumn(0).setPreferredWidth(200);
     78        mod = list.getColumnModel();
     79        mod.getColumn(2).setPreferredWidth(50);
     80        mod.getColumn(1).setPreferredWidth(800);
     81        mod.getColumn(0).setPreferredWidth(200);
    7182
    7283        JPanel buttonPanel = new JPanel(new FlowLayout());
     
    8293                        JOptionPane.OK_CANCEL_OPTION);
    8394                if (answer == JOptionPane.OK_OPTION) {
    84                     model.addRow(new String[]{p.getUrlName(), p.getUrl()});
     95                    model.addRow(new WMSInfo(p.getUrlName(), p.getUrl()));
    8596                }
    8697            }
     
    118129
    119130                outer: for(int i = 0; i < lines.length; i++) {
    120                     String c1 = modeldef.getValueAt(lines[i], 0).toString();
    121                     String c2 = modeldef.getValueAt(lines[i], 1).toString();
     131                    WMSInfo info = modeldef.getRow(lines[i]);
    122132
    123133                    // Check if an entry with exactly the same values already
    124134                    // exists
    125135                    for(int j = 0; j < model.getRowCount(); j++) {
    126                         if(c1.equals(model.getValueAt(j, 0).toString())
    127                                 && c2.equals(model.getValueAt(j, 1).toString())) {
     136                        if(info.equalsBaseValues(model.getRow(j))) {
    128137                            // Select the already existing row so the user has
    129138                            // some feedback in case an entry exists
     
    134143                    }
    135144
    136                     model.addRow(new String[] {c1, c2});
     145                    model.addRow(new WMSInfo(info));
    137146                    int lastLine = model.getRowCount() - 1;
    138147                    list.getSelectionModel().setSelectionInterval(lastLine, lastLine);
     
    151160                "gnome-web-photo --mode=photo --format=png {0} /dev/stdout",
    152161                "gnome-web-photo-fixed {0}",
    153         "webkit-image-gtk {0}"});
     162                "webkit-image-gtk {0}"});
    154163        browser.setEditable(true);
    155164        browser.setSelectedItem(Main.pref.get("wmsplugin.browser", "webkit-image {0}"));
     
    160169        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    161170
    162         overlapCheckBox = new JCheckBox(tr("Overlap tiles"), WMSPlugin.PROP_OVERLAP.get() );
     171        overlapCheckBox = new JCheckBox(tr("Overlap tiles"), plugin.PROP_OVERLAP.get() );
    163172        JLabel labelEast = new JLabel(tr("% of east:"));
    164173        JLabel labelNorth = new JLabel(tr("% of north:"));
    165         spinEast = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_OVERLAP_EAST.get(), 1, 50, 1));
    166         spinNorth = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
     174        spinEast = new JSpinner(new SpinnerNumberModel(plugin.PROP_OVERLAP_EAST.get(), 1, 50, 1));
     175        spinNorth = new JSpinner(new SpinnerNumberModel(plugin.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
    167176
    168177        JPanel overlapPanel = new JPanel(new FlowLayout());
     
    178187        p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    179188        JLabel labelSimConn = new JLabel(tr("Simultaneous connections"));
    180         spinSimConn = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
     189        spinSimConn = new JSpinner(new SpinnerNumberModel(plugin.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
    181190        JPanel overlapPanelSimConn = new JPanel(new FlowLayout());
    182191        overlapPanelSimConn.add(labelSimConn);
     
    191200
    192201        p.add(remotePanel);
    193 
    194202    }
    195203
    196204    public boolean ok() {
    197         boolean change = false;
    198         for (int i = 0; i < model.getRowCount(); ++i) {
    199             String name = model.getValueAt(i,0).toString();
    200             String url = model.getValueAt(i,1).toString();
    201 
    202             WMSInfo origValue = oldValues.get(i);
    203             if (origValue == null)
    204             {
    205                 new WMSInfo(name, url, i).save();
    206                 change = true;
    207             }
    208             else
    209             {
    210                 if (!origValue.name.equals(name) || !origValue.url.equals(url))
    211                 {
    212                     origValue.name = name;
    213                     origValue.url = url;
    214                     origValue.save();
    215                     change = true;
    216                 }
    217                 oldValues.remove(i);
    218             }
    219         }
    220 
    221         // using null values instead of empty string really deletes
    222         // the preferences entry
    223         for (WMSInfo i : oldValues.values())
    224         {
    225             i.url = null;
    226             i.name = null;
    227             i.save();
    228             change = true;
    229         }
    230 
    231         if (change) WMSPlugin.refreshMenu();
    232 
    233         WMSPlugin.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
    234         WMSPlugin.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
    235         WMSPlugin.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
    236         WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
     205        plugin.info.save();
     206        plugin.refreshMenu();
     207
     208        plugin.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
     209        plugin.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
     210        plugin.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
     211        plugin.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
    237212        allowRemoteControl = remoteCheckBox.getModel().isSelected();
    238213
     
    279254        return null;
    280255    }
     256
     257    /**
     258     * The table model for the WMS layer
     259     *
     260     */
     261    class WMSLayerTableModel extends DefaultTableModel {
     262        public WMSLayerTableModel() {
     263            setColumnIdentifiers(new String[]{tr("Menu Name"), tr("WMS URL"), trc("layer", "Zoom")});
     264        }
     265
     266        public WMSInfo getRow(int row) {
     267            return plugin.info.layers.get(row);
     268        }
     269
     270        public void addRow(WMSInfo i) {
     271            plugin.info.add(i);
     272            int p = getRowCount()-1;
     273            fireTableRowsInserted(p,p);
     274        }
     275
     276        public void removeRow(int i) {
     277            plugin.info.remove(getRow(i));
     278            fireTableRowsDeleted(i,i);
     279        }
     280
     281        @Override
     282        public int getRowCount() {
     283            return plugin.info.layers.size();
     284        }
     285
     286        @Override
     287        public Object getValueAt(int row, int column) {
     288            WMSInfo info = plugin.info.layers.get(row);
     289            switch(column) {
     290            case 0: return info.name;
     291            case 1: return info.getFullURL();
     292            case 2: return info.pixelPerDegree == 0.0 ? "" : info.pixelPerDegree;
     293            }
     294            return null;
     295        }
     296
     297        @Override
     298        public boolean isCellEditable(int row, int column) {
     299            return (column != 2);
     300        }
     301    }
     302
     303    /**
     304     * The table model for the WMS layer
     305     *
     306     */
     307    class WMSDefaultLayerTableModel extends DefaultTableModel {
     308        public WMSDefaultLayerTableModel() {
     309            setColumnIdentifiers(new String[]{tr("Menu Name (Default)"), tr("WMS URL (Default)")});
     310        }
     311
     312        public WMSInfo getRow(int row) {
     313            return plugin.info.defaultLayers.get(row);
     314        }
     315
     316        @Override
     317        public int getRowCount() {
     318            return plugin.info.defaultLayers.size();
     319        }
     320
     321        @Override
     322        public Object getValueAt(int row, int column) {
     323            WMSInfo info = plugin.info.defaultLayers.get(row);
     324            switch(column) {
     325            case 0: return info.name;
     326            case 1: return info.getFullURL();
     327            }
     328            return null;
     329        }
     330
     331        @Override
     332        public boolean isCellEditable(int row, int column) {
     333            return false;
     334        }
     335    }
    281336}
    282 
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSRemoteHandler.java

    r22735 r23207  
    1515public class WMSRemoteHandler extends RequestHandler {
    1616
    17         public static final String command = "wms";
     17    public static final String command = "wms";
    1818
    19         @Override
    20         public String getPermissionMessage() {
    21                 return tr("Remote Control has been asked to load a WMS layer from the following URL:") +
    22                 "<br>" + args.get("url");
    23         }
     19    @Override
     20    public String getPermissionMessage() {
     21        return tr("Remote Control has been asked to load a WMS layer from the following URL:") +
     22        "<br>" + args.get("url");
     23    }
    2424
    25         @Override
    26         public PermissionPrefWithDefault getPermissionPref()
    27         {
    28                 return new PermissionPrefWithDefault(
    29                                 "wmsplugin.remotecontrol",
    30                                 true,
    31                 "RemoteControl: WMS forbidden by preferences");
    32         }
     25    @Override
     26    public PermissionPrefWithDefault getPermissionPref()
     27    {
     28        return new PermissionPrefWithDefault(
     29                "wmsplugin.remotecontrol",
     30                true,
     31        "RemoteControl: WMS forbidden by preferences");
     32    }
    3333
    34         @Override
    35         protected String[] getMandatoryParams()
    36         {
    37                 return new String[] { "url" };
    38         }
     34    @Override
     35    protected String[] getMandatoryParams()
     36    {
     37        return new String[] { "url" };
     38    }
    3939
    40         @Override
    41         protected void handleRequest() throws RequestHandlerErrorException {
    42                 String url = args.get("url");
    43                 String title = args.get("title");
    44                 if((title == null) || (title.length() == 0))
    45                 {
    46                         title = "remote WMS";
    47                 }
    48                 String cookies = args.get("cookies");
    49                 if(cookies == null)
    50                 {
    51                         cookies = "";
    52                 }
    53                 WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
    54                 Main.main.addLayer(wmsLayer);
     40    @Override
     41    protected void handleRequest() throws RequestHandlerErrorException {
     42        String url = args.get("url");
     43        String title = args.get("title");
     44        if((title == null) || (title.length() == 0))
     45        {
     46            title = tr("Remote WMS");
     47        }
     48        String cookies = args.get("cookies");
     49        WMSLayer wmsLayer = new WMSLayer(new WMSInfo(title, url, cookies));
     50        Main.main.addLayer(wmsLayer);
    5551
    56         }
     52    }
    5753
    58         @Override
    59         public void parseArgs() {
    60                 StringTokenizer st = new StringTokenizer(request, "&?");
    61                 HashMap<String, String> args = new HashMap<String, String>();
    62                 // skip first element which is the command
    63                 if(st.hasMoreTokens()) st.nextToken();
    64                 while (st.hasMoreTokens()) {
    65                         String param = st.nextToken();
    66                         int eq = param.indexOf("=");
    67                         if (eq > -1)
    68                         {
    69                                 String key = param.substring(0, eq);
    70                                 /* "url=" terminates normal parameters
    71                                 * and will be handled separately
    72                                 */
    73                                 if("url".equals(key)) break;
     54    @Override
     55    public void parseArgs() {
     56        StringTokenizer st = new StringTokenizer(request, "&?");
     57        HashMap<String, String> args = new HashMap<String, String>();
     58        // skip first element which is the command
     59        if(st.hasMoreTokens()) st.nextToken();
     60        while (st.hasMoreTokens()) {
     61            String param = st.nextToken();
     62            int eq = param.indexOf("=");
     63            if (eq > -1)
     64            {
     65                String key = param.substring(0, eq);
     66                /* "url=" terminates normal parameters
     67                * and will be handled separately
     68                */
     69                if("url".equals(key)) break;
    7470
    75                                 String value = param.substring(eq + 1);
    76                                 // urldecode all normal values
    77                                 try {
    78                                         value = URLDecoder.decode(value, "UTF-8");
    79                                 } catch (UnsupportedEncodingException e) {
    80                                         // TODO Auto-generated catch block
    81                                         e.printStackTrace();
    82                                 }
    83                                 args.put(key,
    84                                                 value);
    85                         }
    86                 }
    87                 // url as second or later parameter
    88                 int urlpos = request.indexOf("&url=");
    89                 // url as first (and only) parameter
    90                 if(urlpos < 0) urlpos = request.indexOf("?url=");
    91                 // url found?
    92                 if(urlpos >= 0) {
    93                         // URL value
    94                         String value = request.substring(urlpos + 5);
    95                         // allow skipping URL decoding with urldecode=false
    96                         String urldecode = args.get("urldecode");
    97                         if((urldecode == null) || (Boolean.valueOf(urldecode) == true))
    98                         {
    99                                 try {
    100                                         value = URLDecoder.decode(value, "UTF-8");
    101                                 } catch (UnsupportedEncodingException e) {
    102                                         // TODO Auto-generated catch block
    103                                         e.printStackTrace();
    104                                 }
    105                         }
    106                         args.put("url", value);
    107                 }
    108                 this.args = args;
    109         }
     71                String value = param.substring(eq + 1);
     72                // urldecode all normal values
     73                try {
     74                    value = URLDecoder.decode(value, "UTF-8");
     75                } catch (UnsupportedEncodingException e) {
     76                    // TODO Auto-generated catch block
     77                    e.printStackTrace();
     78                }
     79                args.put(key,
     80                        value);
     81            }
     82        }
     83        // url as second or later parameter
     84        int urlpos = request.indexOf("&url=");
     85        // url as first (and only) parameter
     86        if(urlpos < 0) urlpos = request.indexOf("?url=");
     87        // url found?
     88        if(urlpos >= 0) {
     89            // URL value
     90            String value = request.substring(urlpos + 5);
     91            // allow skipping URL decoding with urldecode=false
     92            String urldecode = args.get("urldecode");
     93            if((urldecode == null) || (Boolean.valueOf(urldecode) == true))
     94            {
     95                try {
     96                    value = URLDecoder.decode(value, "UTF-8");
     97                } catch (UnsupportedEncodingException e) {
     98                    // TODO Auto-generated catch block
     99                    e.printStackTrace();
     100                }
     101            }
     102            args.put("url", value);
     103        }
     104        this.args = args;
     105    }
    110106}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/WMSRequest.java

    r22712 r23207  
    66
    77public class WMSRequest implements Comparable<WMSRequest> {
    8         private final int xIndex;
    9         private final int yIndex;
    10         private final double pixelPerDegree;
    11         private final boolean real; // Download even if autodownloading is disabled
    12         private int priority;
    13         // Result
    14         private State state;
    15         private BufferedImage image;
     8    private final int xIndex;
     9    private final int yIndex;
     10    private final double pixelPerDegree;
     11    private final boolean real; // Download even if autodownloading is disabled
     12    private int priority;
     13    // Result
     14    private State state;
     15    private BufferedImage image;
    1616
    17         public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real) {
    18                 this.xIndex = xIndex;
    19                 this.yIndex = yIndex;
    20                 this.pixelPerDegree = pixelPerDegree;
    21                 this.real = real;
    22         }
     17    public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real) {
     18        this.xIndex = xIndex;
     19        this.yIndex = yIndex;
     20        this.pixelPerDegree = pixelPerDegree;
     21        this.real = real;
     22    }
    2323
    24         public void finish(State state, BufferedImage image) {
    25                 this.state = state;
    26                 this.image = image;
    27         }
     24    public void finish(State state, BufferedImage image) {
     25        this.state = state;
     26        this.image = image;
     27    }
    2828
    29         public int getXIndex() {
    30                 return xIndex;
    31         }
     29    public int getXIndex() {
     30        return xIndex;
     31    }
    3232
    33         public int getYIndex() {
    34                 return yIndex;
    35         }
     33    public int getYIndex() {
     34        return yIndex;
     35    }
    3636
    37         public double getPixelPerDegree() {
    38                 return pixelPerDegree;
    39         }
     37    public double getPixelPerDegree() {
     38        return pixelPerDegree;
     39    }
    4040
    41         @Override
    42         public int hashCode() {
    43                 final int prime = 31;
    44                 int result = 1;
    45                 long temp;
    46                 temp = Double.doubleToLongBits(pixelPerDegree);
    47                 result = prime * result + (int) (temp ^ (temp >>> 32));
    48                 result = prime * result + xIndex;
    49                 result = prime * result + yIndex;
    50                 return result;
    51         }
     41    @Override
     42    public int hashCode() {
     43        final int prime = 31;
     44        int result = 1;
     45        long temp;
     46        temp = Double.doubleToLongBits(pixelPerDegree);
     47        result = prime * result + (int) (temp ^ (temp >>> 32));
     48        result = prime * result + xIndex;
     49        result = prime * result + yIndex;
     50        return result;
     51    }
    5252
    53         @Override
    54         public boolean equals(Object obj) {
    55                 if (this == obj)
    56                         return true;
    57                 if (obj == null)
    58                         return false;
    59                 if (getClass() != obj.getClass())
    60                         return false;
    61                 WMSRequest other = (WMSRequest) obj;
    62                 if (Double.doubleToLongBits(pixelPerDegree) != Double
    63                                 .doubleToLongBits(other.pixelPerDegree))
    64                         return false;
    65                 if (xIndex != other.xIndex)
    66                         return false;
    67                 if (yIndex != other.yIndex)
    68                         return false;
    69                 return true;
    70         }
     53    @Override
     54    public boolean equals(Object obj) {
     55        if (this == obj)
     56            return true;
     57        if (obj == null)
     58            return false;
     59        if (getClass() != obj.getClass())
     60            return false;
     61        WMSRequest other = (WMSRequest) obj;
     62        if (Double.doubleToLongBits(pixelPerDegree) != Double
     63                .doubleToLongBits(other.pixelPerDegree))
     64            return false;
     65        if (xIndex != other.xIndex)
     66            return false;
     67        if (yIndex != other.yIndex)
     68            return false;
     69        return true;
     70    }
    7171
    72         public void setPriority(int priority) {
    73                 this.priority = priority;
    74         }
     72    public void setPriority(int priority) {
     73        this.priority = priority;
     74    }
    7575
    76         public int getPriority() {
    77                 return priority;
    78         }
     76    public int getPriority() {
     77        return priority;
     78    }
    7979
    80         public int compareTo(WMSRequest o) {
    81                 return priority - o.priority;
    82         }
     80    public int compareTo(WMSRequest o) {
     81        return priority - o.priority;
     82    }
    8383
    84         public State getState() {
    85                 return state;
    86         }
     84    public State getState() {
     85        return state;
     86    }
    8787
    88         public BufferedImage getImage() {
    89                 return image;
    90         }
     88    public BufferedImage getImage() {
     89        return image;
     90    }
    9191
    92         @Override
    93         public String toString() {
    94                 return "WMSRequest [xIndex=" + xIndex + ", yIndex=" + yIndex
    95                 + ", pixelPerDegree=" + pixelPerDegree + "]";
    96         }
     92    @Override
     93    public String toString() {
     94        return "WMSRequest [xIndex=" + xIndex + ", yIndex=" + yIndex
     95        + ", pixelPerDegree=" + pixelPerDegree + "]";
     96    }
    9797
    98         public boolean isReal() {
    99                 return real;
    100         }
     98    public boolean isReal() {
     99        return real;
     100    }
    101101}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/io/WMSLayerExporter.java

    r17397 r23207  
    77
    88public class WMSLayerExporter extends FileExporter{
    9        
    10         public WMSLayerExporter() {
    11                 super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
    12         }
     9   
     10    public WMSLayerExporter() {
     11        super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
     12    }
    1313}
  • applications/editors/josm/plugins/wmsplugin/src/wmsplugin/io/WMSLayerImporter.java

    r17397 r23207  
    77public class WMSLayerImporter extends FileImporter{
    88
    9         public WMSLayerImporter() {
    10                 super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
    11         }
    12        
     9    public WMSLayerImporter() {
     10        super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
     11    }
     12   
    1313}
Note: See TracChangeset for help on using the changeset viewer.