Changeset 1704 in josm


Ignore:
Timestamp:
Jun 27, 2009 11:46:17 AM (4 years ago)
Author:
stoecker
Message:

fix #2674, #765 - patch by jttt - reworked GeoImage stuff

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java

    r1590 r1704  
    2525import java.awt.event.MouseEvent; 
    2626import java.awt.image.BufferedImage; 
     27import java.awt.image.ImageObserver; 
    2728import java.io.File; 
    2829import java.io.IOException; 
     30import java.lang.ref.SoftReference; 
    2931import java.text.ParseException; 
    3032import java.text.SimpleDateFormat; 
     
    3436import java.util.Date; 
    3537import java.util.LinkedList; 
     38import java.util.List; 
     39import java.util.WeakHashMap; 
    3640 
    3741import javax.swing.BorderFactory; 
     
    5256import javax.swing.JToggleButton; 
    5357import javax.swing.JViewport; 
     58import javax.swing.ScrollPaneConstants; 
    5459import javax.swing.border.BevelBorder; 
    5560import javax.swing.border.Border; 
     
    6772import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 
    6873import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 
     74import org.openstreetmap.josm.gui.layer.GeoImageLayer.ImageLoader.ImageLoadedListener; 
    6975import org.openstreetmap.josm.tools.DateParser; 
    7076import org.openstreetmap.josm.tools.ExifReader; 
     
    7985public class GeoImageLayer extends Layer { 
    8086 
    81     private static final class ImageEntry implements Comparable<ImageEntry> { 
    82         File image; 
     87    /** 
     88     * Allows to load and scale images. Loaded images are kept in cache (using soft reference). Both 
     89     * synchronous and asynchronous loading is supported 
     90     * 
     91     */ 
     92    public static class ImageLoader implements ImageObserver { 
     93 
     94        public static class Entry { 
     95            final File file; 
     96            final int width; 
     97            final int height; 
     98            final int maxSize; 
     99            private final ImageLoadedListener listener; 
     100 
     101            volatile Image scaledImage; 
     102 
     103 
     104            public Entry(File file, int width, int height, int maxSize, ImageLoadedListener listener) { 
     105                this.file = file; 
     106                this.height = height; 
     107                this.width = width; 
     108                this.maxSize = maxSize; 
     109                this.listener = listener; 
     110            } 
     111        } 
     112 
     113        public interface ImageLoadedListener { 
     114            void imageLoaded(); 
     115        } 
     116 
     117        private final List<ImageLoader.Entry> queue = new ArrayList<ImageLoader.Entry>(); 
     118        private final WeakHashMap<File, SoftReference<Image>> loadedImageCache = new WeakHashMap<File, SoftReference<Image>>(); 
     119        private ImageLoader.Entry currentEntry; 
     120 
     121        private Image getOrLoadImage(File file) { 
     122            SoftReference<Image> cachedImageRef = loadedImageCache.get(file); 
     123            if (cachedImageRef != null) { 
     124                Image cachedImage = cachedImageRef.get(); 
     125                if (cachedImage != null) { 
     126                    return cachedImage; 
     127                } 
     128            } 
     129            return Toolkit.getDefaultToolkit().createImage(currentEntry.file.getAbsolutePath()); 
     130        } 
     131 
     132        private BufferedImage createResizedCopy(Image originalImage, 
     133                int scaledWidth, int scaledHeight) 
     134        { 
     135            BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB); 
     136            Graphics2D g = scaledBI.createGraphics(); 
     137            while (!g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null)) 
     138            { 
     139                try { 
     140                    Thread.sleep(10); 
     141                } catch(InterruptedException ie) {} 
     142            } 
     143            g.dispose(); 
     144            return scaledBI; 
     145        } 
     146        private void loadImage() { 
     147            if (currentEntry != null) { 
     148                return; 
     149            } 
     150            while (!queue.isEmpty()) { 
     151                currentEntry = queue.get(0); 
     152                queue.remove(0); 
     153 
     154                Image newImage = getOrLoadImage(currentEntry.file); 
     155                if (newImage.getWidth(this) == -1) { 
     156                    break; 
     157                } else { 
     158                    finishImage(newImage, currentEntry); 
     159                    currentEntry = null; 
     160                } 
     161            } 
     162        } 
     163 
     164        private void finishImage(Image img, ImageLoader.Entry entry) { 
     165            loadedImageCache.put(entry.file, new SoftReference<Image>(img)); 
     166            if (entry.maxSize != -1) { 
     167                int w = img.getWidth(null); 
     168                int h = img.getHeight(null); 
     169                if (w>h) { 
     170                    h = Math.round(entry.maxSize*((float)h/w)); 
     171                    w = entry.maxSize; 
     172                } else { 
     173                    w = Math.round(entry.maxSize*((float)w/h)); 
     174                    h = entry.maxSize; 
     175                } 
     176                entry.scaledImage = createResizedCopy(img, w, h); 
     177            } else if (entry.width != -1 && entry.height != -1) { 
     178                entry.scaledImage = createResizedCopy(img, entry.width, entry.height); 
     179            } else { 
     180                entry.scaledImage = img; 
     181            } 
     182            if (entry.listener != null) { 
     183                entry.listener.imageLoaded(); 
     184            } 
     185        } 
     186 
     187        public synchronized ImageLoader.Entry loadImage(File file, int width, int height, int maxSize, ImageLoadedListener listener) { 
     188            ImageLoader.Entry e = new Entry(file, width, height, maxSize, listener); 
     189            queue.add(e); 
     190            loadImage(); 
     191            return e; 
     192        } 
     193 
     194        public Image waitForImage(File file, int width, int height) { 
     195            return waitForImage(file, width, height, -1); 
     196        } 
     197 
     198        public Image waitForImage(File file, int maxSize) { 
     199            return waitForImage(file, -1, -1, maxSize); 
     200        } 
     201 
     202        public Image waitForImage(File file) { 
     203            return waitForImage(file, -1, -1, -1); 
     204        } 
     205 
     206        private synchronized Image waitForImage(File file, int width, int height, int maxSize) { 
     207            ImageLoader.Entry entry; 
     208            if (currentEntry != null && currentEntry.file.equals(file)) { 
     209                entry = currentEntry; 
     210            } else { 
     211                entry = new Entry(file, width, height, maxSize, null); 
     212                queue.add(0, entry); 
     213            } 
     214            loadImage(); 
     215 
     216            while (true) { 
     217                if (entry.scaledImage != null) { 
     218                    return entry.scaledImage; 
     219                } 
     220                try { 
     221                    wait(); 
     222                } catch (InterruptedException e) {} 
     223            } 
     224        } 
     225 
     226        public synchronized boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { 
     227            if ((infoflags & ImageObserver.ALLBITS) != 0) { 
     228                finishImage(img, currentEntry); 
     229                currentEntry = null; 
     230                loadImage(); 
     231                notifyAll(); 
     232            } 
     233            return true; 
     234        } 
     235    } 
     236 
     237    private static final int ICON_SIZE = 16; 
     238    private static ImageLoader imageLoader = new ImageLoader(); 
     239 
     240    private static final class ImageEntry implements Comparable<ImageEntry>, ImageLoadedListener { 
     241 
     242        private static final Image EMPTY_IMAGE = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY); 
     243 
     244        final File image; 
     245        ImageLoader.Entry icon; 
     246 
    83247        Date time; 
    84248        LatLon coor; 
    85249        EastNorth pos; 
    86         Icon icon; 
     250 
     251        public ImageEntry(File image) { 
     252            this.image = image; 
     253            icon = imageLoader.loadImage(image, ICON_SIZE, ICON_SIZE, -1, this); 
     254        } 
     255 
    87256        public int compareTo(ImageEntry image) { 
    88257            return time.compareTo(image.time); 
     258        } 
     259 
     260        public Image getIcon() { 
     261            if (icon.scaledImage == null) { 
     262                return EMPTY_IMAGE; 
     263            } else { 
     264                return icon.scaledImage; 
     265            } 
     266        } 
     267 
     268        public void imageLoaded() { 
     269            Main.map.mapView.repaint(); 
    89270        } 
    90271    } 
     
    109290                for (Collection<WayPoint> segment : trk.trackSegs) { 
    110291                    for (WayPoint p : segment) { 
    111                     if (!p.attr.containsKey("time")) 
    112                         throw new IOException(tr("No time for point {0} x {1}",p.latlon.lat(),p.latlon.lon())); 
    113                     Date d = null; 
    114                     try { 
    115                         d = DateParser.parse((String) p.attr.get("time")); 
    116                     } catch (ParseException e) { 
    117                         throw new IOException(tr("Cannot read time \"{0}\" from point {1} x {2}",p.attr.get("time"),p.latlon.lat(),p.latlon.lon())); 
     292                        if (!p.attr.containsKey("time")) 
     293                            throw new IOException(tr("No time for point {0} x {1}",p.latlon.lat(),p.latlon.lon())); 
     294                        Date d = null; 
     295                        try { 
     296                            d = DateParser.parse((String) p.attr.get("time")); 
     297                        } catch (ParseException e) { 
     298                            throw new IOException(tr("Cannot read time \"{0}\" from point {1} x {2}",p.attr.get("time"),p.latlon.lat(),p.latlon.lon())); 
     299                        } 
     300                        gps.add(new TimedPoint(d, p.eastNorth)); 
    118301                    } 
    119                     gps.add(new TimedPoint(d, p.eastNorth)); 
    120                 } 
    121             } 
     302                } 
    122303            } 
    123304 
     
    137318                Main.pleaseWaitDlg.progress.setValue(i++); 
    138319 
    139                 ImageEntry e = new ImageEntry(); 
     320                ImageEntry e = new ImageEntry(f); 
    140321                try { 
    141322                    e.time = ExifReader.readTime(f); 
     
    145326                if (e.time == null) 
    146327                    continue; 
    147                 e.image = f; 
    148                 e.icon = loadScaledImage(f, 16); 
    149328 
    150329                data.add(e); 
     
    172351    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); 
    173352    private MouseAdapter mouseAdapter; 
    174     private int currentImage; 
     353    private ImageViewerDialog imageViewerDialog; 
    175354 
    176355    public static final class GpsTimeIncorrect extends Exception { 
     
    226405                        continue; 
    227406                    Point p = Main.map.mapView.getPoint(e.pos); 
    228                     Rectangle r = new Rectangle(p.x-e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight()); 
     407                    Rectangle r = new Rectangle(p.x-ICON_SIZE/2, p.y-ICON_SIZE/2, ICON_SIZE, ICON_SIZE); 
    229408                    if (r.contains(ev.getPoint())) { 
    230409                        showImage(i-1); 
     
    246425    } 
    247426 
     427    private class ImageViewerDialog { 
     428 
     429        private int currentImage; 
     430        private ImageEntry currentImageEntry; 
     431 
     432        private final JDialog dlg; 
     433        private final JButton nextButton; 
     434        private final JButton prevButton; 
     435        private final JToggleButton scaleToggle; 
     436        private final JToggleButton centerToggle; 
     437        private final JViewport imageViewport; 
     438        private final JLabel imageLabel; 
     439 
     440        private class ImageAction implements ActionListener { 
     441 
     442            private final int offset; 
     443 
     444            public ImageAction(int offset) { 
     445                this.offset = offset; 
     446            } 
     447 
     448            public void actionPerformed(ActionEvent e) { 
     449                showImage(currentImage + offset); 
     450            } 
     451 
     452        } 
     453 
     454        public ImageViewerDialog(ImageEntry firstImage) { 
     455            final JPanel p = new JPanel(new BorderLayout()); 
     456            imageLabel = new JLabel(new ImageIcon(imageLoader.waitForImage(firstImage.image, 580))); 
     457            final JScrollPane scroll = new JScrollPane(imageLabel); 
     458            scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 
     459            scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
     460            imageViewport = scroll.getViewport(); 
     461            p.add(scroll, BorderLayout.CENTER); 
     462 
     463            scaleToggle = new JToggleButton(ImageProvider.get("dialogs", "zoom-best-fit")); 
     464            nextButton  = new JButton(ImageProvider.get("dialogs", "next")); 
     465            prevButton = new JButton(ImageProvider.get("dialogs", "previous")); 
     466            centerToggle = new JToggleButton(ImageProvider.get("dialogs", "centreview")); 
     467 
     468            JPanel p2 = new JPanel(); 
     469            p2.add(prevButton); 
     470            p2.add(scaleToggle); 
     471            p2.add(centerToggle); 
     472            p2.add(nextButton); 
     473            p.add(p2, BorderLayout.SOUTH); 
     474            final JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE); 
     475            dlg = pane.createDialog(Main.parent, ""); 
     476            scaleToggle.addActionListener(new ImageAction(0)); 
     477            scaleToggle.setSelected(true); 
     478            centerToggle.addActionListener(new ImageAction(0)); 
     479 
     480            nextButton.setActionCommand("Next"); 
     481            prevButton.setActionCommand("Previous"); 
     482            nextButton.setMnemonic(KeyEvent.VK_RIGHT); 
     483            prevButton.setMnemonic(KeyEvent.VK_LEFT); 
     484            scaleToggle.setMnemonic(KeyEvent.VK_F); 
     485            centerToggle.setMnemonic(KeyEvent.VK_C); 
     486            nextButton.setToolTipText("Show next image"); 
     487            prevButton.setToolTipText("Show previous image"); 
     488            centerToggle.setToolTipText("Centre image location in main display"); 
     489            scaleToggle.setToolTipText("Scale image to fit"); 
     490 
     491            prevButton.addActionListener(new ImageAction(-1)); 
     492            nextButton.addActionListener(new ImageAction(1)); 
     493            centerToggle.setSelected(false); 
     494 
     495            dlg.addComponentListener(new ComponentListener() { 
     496                boolean ignoreEvent = true; 
     497                public void componentHidden(ComponentEvent e) {} 
     498                public void componentMoved(ComponentEvent e) {} 
     499                public void componentResized(ComponentEvent ev) { 
     500                    // we ignore the first resize event, as the picture is scaled already on load: 
     501                    if (scaleToggle.getModel().isSelected() && !ignoreEvent) { 
     502                        imageLabel.setIcon(new ImageIcon(imageLoader.waitForImage(currentImageEntry.image, 
     503                                Math.max(imageViewport.getWidth(), imageViewport.getHeight())))); 
     504                    } 
     505                    ignoreEvent = false; 
     506                } 
     507                public void componentShown(ComponentEvent e) {} 
     508 
     509            }); 
     510            dlg.setModal(false); 
     511            dlg.setResizable(true); 
     512            dlg.pack(); 
     513        } 
     514 
     515        public void showImage(int index) { 
     516            dlg.setVisible(true); 
     517            dlg.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
     518 
     519            if (index < 0) { 
     520                index = 0; 
     521            } else if (index >= data.size() - 1) { 
     522                index = data.size() - 1; 
     523            } 
     524 
     525            currentImage = index; 
     526            currentImageEntry = data.get(currentImage); 
     527 
     528            prevButton.setEnabled(currentImage > 0); 
     529            nextButton.setEnabled(currentImage < data.size() - 1); 
     530 
     531            if (scaleToggle.getModel().isSelected()) 
     532                imageLabel.setIcon(new ImageIcon(imageLoader.waitForImage(currentImageEntry.image, 
     533                        Math.max(imageViewport.getWidth(), imageViewport.getHeight())))); 
     534            else 
     535                imageLabel.setIcon(new ImageIcon(imageLoader.waitForImage(currentImageEntry.image))); 
     536 
     537            if (centerToggle.getModel().isSelected()) 
     538                Main.map.mapView.zoomTo(currentImageEntry.pos, Main.map.mapView.getScale()); 
     539 
     540            dlg.setTitle(currentImageEntry.image + 
     541                    " (" + currentImageEntry.coor.toDisplayString() + ")"); 
     542            dlg.setCursor(Cursor.getDefaultCursor()); 
     543        } 
     544 
     545    } 
     546 
    248547    private void showImage(int i) { 
    249         currentImage = i; 
    250         final JPanel p = new JPanel(new BorderLayout()); 
    251         final ImageEntry e = data.get(currentImage); 
    252         if (!(e.image.exists() && e.image.canRead())) 
    253         { 
    254             JOptionPane.showMessageDialog(Main.parent, 
    255             tr("Image with path {0} does not exist or is not readable.", e.image), 
    256             tr("Warning"), JOptionPane.WARNING_MESSAGE); 
    257             return; 
    258         } 
    259         final JScrollPane scroll = new JScrollPane(new JLabel(loadScaledImage(e.image, 580))); 
    260         final JViewport vp = scroll.getViewport(); 
    261         p.add(scroll, BorderLayout.CENTER); 
    262  
    263         final JToggleButton scale = new JToggleButton(ImageProvider.get("dialogs", "zoom-best-fit")); 
    264         final JButton next  = new JButton(ImageProvider.get("dialogs", "next")); 
    265         final JButton prev = new JButton(ImageProvider.get("dialogs", "previous")); 
    266         final JToggleButton cent = new JToggleButton(ImageProvider.get("dialogs", "centreview")); 
    267  
    268         JPanel p2 = new JPanel(); 
    269         p2.add(prev); 
    270         p2.add(scale); 
    271         p2.add(cent); 
    272         p2.add(next); 
    273         prev.setEnabled(currentImage>0?true:false); 
    274         next.setEnabled(currentImage<data.size()-1?true:false); 
    275         p.add(p2, BorderLayout.SOUTH); 
    276         final JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE); 
    277         final JDialog dlg = pane.createDialog(Main.parent, e.image+" ("+e.coor.toDisplayString()+")"); 
    278         scale.addActionListener(new ActionListener(){ 
    279             public void actionPerformed(ActionEvent ev) { 
    280                 p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
    281                 if (scale.getModel().isSelected()) 
    282                     ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight()))); 
    283                 else 
    284                     ((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath())); 
    285                 p.setCursor(Cursor.getDefaultCursor()); 
    286             } 
    287         }); 
    288         scale.setSelected(true); 
    289         cent.addActionListener(new ActionListener(){ 
    290             public void actionPerformed(ActionEvent ev) { 
    291                 final ImageEntry e = data.get(currentImage); 
    292                 if (cent.getModel().isSelected()) 
    293                     Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale()); 
    294             } 
    295         }); 
    296  
    297         ActionListener nextprevAction = new ActionListener(){ 
    298             public void actionPerformed(ActionEvent ev) { 
    299                 p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
    300                 if (ev.getActionCommand().equals("Next")) { 
    301                     currentImage++; 
    302                     if(currentImage>=data.size()-1) next.setEnabled(false); 
    303                     prev.setEnabled(true); 
    304                 } else { 
    305                     currentImage--; 
    306                     if(currentImage<=0) prev.setEnabled(false); 
    307                     next.setEnabled(true); 
    308                 } 
    309  
    310                 final ImageEntry e = data.get(currentImage); 
    311                 if (scale.getModel().isSelected()) 
    312                     ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight()))); 
    313                 else 
    314                     ((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath())); 
    315                 dlg.setTitle(e.image+" ("+e.coor.toDisplayString()+")"); 
    316                 if (cent.getModel().isSelected()) 
    317                     Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale()); 
    318                 p.setCursor(Cursor.getDefaultCursor()); 
    319             } 
    320         }; 
    321         next.setActionCommand("Next"); 
    322         prev.setActionCommand("Previous"); 
    323         next.setMnemonic(KeyEvent.VK_RIGHT); 
    324         prev.setMnemonic(KeyEvent.VK_LEFT); 
    325         scale.setMnemonic(KeyEvent.VK_F); 
    326         cent.setMnemonic(KeyEvent.VK_C); 
    327         next.setToolTipText("Show next image"); 
    328         prev.setToolTipText("Show previous image"); 
    329         cent.setToolTipText("Centre image location in main display"); 
    330         scale.setToolTipText("Scale image to fit"); 
    331  
    332         prev.addActionListener(nextprevAction); 
    333         next.addActionListener(nextprevAction); 
    334         cent.setSelected(false); 
    335  
    336         dlg.addComponentListener(new ComponentListener() { 
    337             boolean ignoreEvent = true; 
    338             public void componentHidden(ComponentEvent e) {} 
    339             public void componentMoved(ComponentEvent e) {} 
    340             public void componentResized(ComponentEvent ev) { 
    341                 // we ignore the first resize event, as the picture is scaled already on load: 
    342                 if (scale.getModel().isSelected() && !ignoreEvent) { 
    343                     ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight()))); 
    344                 } 
    345                 ignoreEvent = false; 
    346             } 
    347             public void componentShown(ComponentEvent e) {} 
    348  
    349         }); 
    350         dlg.setModal(false); 
    351         dlg.setVisible(true); 
    352         dlg.setResizable(true); 
     548        if (imageViewerDialog == null) { 
     549            imageViewerDialog = new ImageViewerDialog(data.get(i)); 
     550        } 
     551        imageViewerDialog.showImage(i); 
    353552    } 
    354553 
     
    372571                super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 
    373572                ImageEntry e = (ImageEntry)value; 
    374                 setIcon(e.icon); 
     573                setIcon(new ImageIcon(e.getIcon())); 
    375574                setText(e.image.getName()+" ("+dateFormat.format(new Date(e.time.getTime()+(delta+gpstimezone)))+")"); 
    376575                if (e.pos == null) 
     
    402601 
    403602    @Override public void paint(Graphics g, MapView mv) { 
    404         boolean clickedFound = false; 
    405         for (ImageEntry e : data) { 
     603        int clickedIndex = -1; 
     604 
     605        // First select beveled icon (for cases where are more icons on the same spot) 
     606        Point mousePosition = mv.getMousePosition(); 
     607        if (mousePosition != null  && mousePressed) { 
     608            for (int i = data.size() - 1; i >= 0; i--) { 
     609                ImageEntry e = data.get(i); 
     610                if (e.pos == null) { 
     611                    continue; 
     612                } 
     613 
     614                Point p = mv.getPoint(e.pos); 
     615                Rectangle r = new Rectangle(p.x-ICON_SIZE / 2, p.y-ICON_SIZE / 2, ICON_SIZE, ICON_SIZE); 
     616                if (r.contains(mousePosition)) { 
     617                    clickedIndex = i; 
     618                    break; 
     619                } 
     620            } 
     621        } 
     622 
     623        for (int i = 0; i < data.size(); i++) { 
     624            ImageEntry e = data.get(i); 
    406625            if (e.pos != null) { 
    407626                Point p = mv.getPoint(e.pos); 
    408                 Rectangle r = new Rectangle(p.x-e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight()); 
    409                 e.icon.paintIcon(mv, g, r.x, r.y); 
     627                Rectangle r = new Rectangle(p.x-ICON_SIZE / 2, p.y-ICON_SIZE / 2, ICON_SIZE, ICON_SIZE); 
     628                g.drawImage(e.getIcon(), r.x, r.y, null); 
    410629                Border b = null; 
    411                 Point mousePosition = mv.getMousePosition(); 
    412                 if (mousePosition == null) 
    413                     continue; // mouse outside the whole window 
    414                 if (!clickedFound && mousePressed && r.contains(mousePosition)) { 
     630                if (i == clickedIndex) { 
    415631                    b = BorderFactory.createBevelBorder(BevelBorder.LOWERED); 
    416                     clickedFound = true; 
    417                 } else 
     632                } else { 
    418633                    b = BorderFactory.createBevelBorder(BevelBorder.RAISED); 
     634                } 
    419635                Insets inset = b.getBorderInsets(mv); 
    420636                r.grow((inset.top+inset.bottom)/2, (inset.left+inset.right)/2); 
     
    477693                lastTP = tp; 
    478694            } 
    479             if (e.pos != null) 
    480                 e.coor = Main.proj.eastNorth2latlon(e.pos); 
     695            if (e.pos == null) { 
     696                e.pos = gps.getLast().pos; 
     697            } 
     698            e.coor = Main.proj.eastNorth2latlon(e.pos); 
    481699        } 
    482700    } 
     
    496714        JPanel p = new JPanel(new GridBagLayout()); 
    497715        p.add(new JLabel(tr("Image")), GBC.eol()); 
    498         p.add(new JLabel(loadScaledImage(f, 300)), GBC.eop()); 
     716        p.add(new JLabel(new ImageIcon(imageLoader.waitForImage(f, 300))), GBC.eop()); 
    499717        p.add(new JLabel(tr("Enter shown date (mm/dd/yyyy HH:MM:SS)")), GBC.eol()); 
    500718        JTextField gpsText = new JTextField(dateFormat.format(new Date(exifDate.getTime()+delta))); 
     
    531749    } 
    532750 
    533     private static Icon loadScaledImage(File f, int maxSize) { 
    534         Image img = Toolkit.getDefaultToolkit().createImage(f.getPath()); 
    535         while (img.getWidth(null) < 0 || img.getHeight(null) < 0) { 
    536           try { 
    537             Thread.sleep(10); 
    538           } catch(InterruptedException ie) {} 
    539         } 
    540         int w = img.getWidth(null); 
    541         int h = img.getHeight(null); 
    542         if (w>h) { 
    543             h = Math.round(maxSize*((float)h/w)); 
    544             w = maxSize; 
    545         } else { 
    546             w = Math.round(maxSize*((float)w/h)); 
    547             h = maxSize; 
    548         } 
    549         return new ImageIcon(createResizedCopy(img, w, h)); 
    550     } 
    551  
    552     private static BufferedImage createResizedCopy(Image originalImage, 
    553     int scaledWidth, int scaledHeight) 
    554     { 
    555         BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB); 
    556         Graphics2D g = scaledBI.createGraphics(); 
    557         while (!g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null)) 
    558         { 
    559           try { 
    560             Thread.sleep(10); 
    561           } catch(InterruptedException ie) {} 
    562         } 
    563         g.dispose(); 
    564         return scaledBI; 
    565     } 
    566751} 
Note: See TracChangeset for help on using the changeset viewer.