Ignore:
Timestamp:
2015-07-01T13:55:52+02:00 (9 years ago)
Author:
nokutu
Message:

Fixed concurrency bug when downloading images

Location:
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySequenceDownloadThread.java

    r31322 r31326  
    3131public class MapillarySequenceDownloadThread implements Runnable {
    3232
    33         private final String url;
    34         private final ExecutorService ex;
    35         private final List<Bounds> bounds;
    36         private final MapillaryLayer layer;
    37         private final MapillarySquareDownloadManagerThread manager;
     33    private final String url;
     34    private final ExecutorService ex;
     35    private final List<Bounds> bounds;
     36    private final MapillaryLayer layer;
     37    private final MapillarySquareDownloadManagerThread manager;
    3838
    39         public MapillarySequenceDownloadThread(ExecutorService ex, String url,
    40                         MapillaryLayer layer, MapillarySquareDownloadManagerThread manager) {
    41                 this.url = url;
    42                 this.ex = ex;
    43                 this.bounds = layer.bounds;
    44                 this.layer = layer;
    45                 this.manager = manager;
    46         }
     39    public MapillarySequenceDownloadThread(ExecutorService ex, String url,
     40            MapillaryLayer layer, MapillarySquareDownloadManagerThread manager) {
     41        this.url = url;
     42        this.ex = ex;
     43        this.bounds = layer.bounds;
     44        this.layer = layer;
     45        this.manager = manager;
     46    }
    4747
    48         public void run() {
    49                 try {
    50                         BufferedReader br;
    51                         br = new BufferedReader(new InputStreamReader(
    52                                         new URL(url).openStream()));
    53                         JsonObject jsonall = Json.createReader(br).readObject();
     48    public void run() {
     49        try {
     50            BufferedReader br;
     51            br = new BufferedReader(new InputStreamReader(
     52                    new URL(url).openStream()));
     53            JsonObject jsonall = Json.createReader(br).readObject();
    5454
    55                         if (!jsonall.getBoolean("more") && !ex.isShutdown())
    56                                 ex.shutdown();
    57                         JsonArray jsonseq = jsonall.getJsonArray("ss");
    58                         boolean isSequenceWrong = false;
    59                         for (int i = 0; i < jsonseq.size(); i++) {
    60                                 JsonObject jsonobj = jsonseq.getJsonObject(i);
    61                                 JsonArray cas = jsonobj.getJsonArray("cas");
    62                                 JsonArray coords = jsonobj.getJsonArray("coords");
    63                                 JsonArray keys = jsonobj.getJsonArray("keys");
    64                                 ArrayList<MapillaryImage> images = new ArrayList<>();
    65                                 for (int j = 0; j < cas.size(); j++) {
    66                                         try {
    67                                                 images.add(new MapillaryImage(keys.getString(j),
    68                                                                 coords.getJsonArray(j).getJsonNumber(1)
    69                                                                                 .doubleValue(), coords.getJsonArray(j)
    70                                                                                 .getJsonNumber(0).doubleValue(), cas
    71                                                                                 .getJsonNumber(j).doubleValue()));
    72                                         } catch (IndexOutOfBoundsException e) {
    73                                                 Main.warn("Mapillary bug at " + url);
    74                                                 isSequenceWrong = true;
    75                                         }
    76                                 }
    77                                 if (isSequenceWrong)
    78                                         break;
    79                                 MapillarySequence sequence = new MapillarySequence(
    80                                                 jsonobj.getString("key"), jsonobj.getJsonNumber(
    81                                                                 "captured_at").longValue());
     55            if (!jsonall.getBoolean("more") && !ex.isShutdown())
     56                ex.shutdown();
     57            JsonArray jsonseq = jsonall.getJsonArray("ss");
     58            boolean isSequenceWrong = false;
     59            for (int i = 0; i < jsonseq.size(); i++) {
     60                JsonObject jsonobj = jsonseq.getJsonObject(i);
     61                JsonArray cas = jsonobj.getJsonArray("cas");
     62                JsonArray coords = jsonobj.getJsonArray("coords");
     63                JsonArray keys = jsonobj.getJsonArray("keys");
     64                ArrayList<MapillaryImage> images = new ArrayList<>();
     65                for (int j = 0; j < cas.size(); j++) {
     66                    try {
     67                        images.add(new MapillaryImage(keys.getString(j),
     68                                coords.getJsonArray(j).getJsonNumber(1)
     69                                        .doubleValue(), coords.getJsonArray(j)
     70                                        .getJsonNumber(0).doubleValue(), cas
     71                                        .getJsonNumber(j).doubleValue()));
     72                    } catch (IndexOutOfBoundsException e) {
     73                        Main.warn("Mapillary bug at " + url);
     74                        isSequenceWrong = true;
     75                    }
     76                }
     77                if (isSequenceWrong)
     78                    break;
     79                MapillarySequence sequence = new MapillarySequence(
     80                        jsonobj.getString("key"), jsonobj.getJsonNumber(
     81                                "captured_at").longValue());
    8282
    83                                 List<MapillaryImage> finalImages = new ArrayList<>(images);
    84                                 // Here it gets only those images which are in the downloaded
    85                                 // area.
    86                                 for (MapillaryAbstractImage img : images) {
    87                                         if (!isInside(img))
    88                                                 finalImages.remove(img);
    89                                 }
     83                List<MapillaryImage> finalImages = new ArrayList<>(images);
     84                // Here it gets only those images which are in the downloaded
     85                // area.
     86                for (MapillaryAbstractImage img : images) {
     87                    if (!isInside(img))
     88                        finalImages.remove(img);
     89                }
    9090
    91                                 boolean imagesAdded = false;
    92                                 for (MapillaryImage img : finalImages) {
    93                                         if (layer.data.getImages().contains(img)) {
    94                                                 ((MapillaryImage) layer.data.getImages().get(
    95                                                                 layer.data.getImages().indexOf(img)))
    96                                                                 .setSequence(sequence);
    97                                                 finalImages.set(
    98                                                                 finalImages.indexOf(img),
    99                                                                 (MapillaryImage) layer.data.getImages().get(
    100                                                                                 layer.data.getImages().indexOf(img)));
    101                                         }
     91                boolean imagesAdded = false;
     92                for (MapillaryImage img : finalImages) {
     93                    if (layer.data.getImages().contains(img)) {
     94                        ((MapillaryImage) layer.data.getImages().get(
     95                                layer.data.getImages().indexOf(img)))
     96                                .setSequence(sequence);
     97                        finalImages.set(
     98                                finalImages.indexOf(img),
     99                                (MapillaryImage) layer.data.getImages().get(
     100                                        layer.data.getImages().indexOf(img)));
     101                        sequence.add(img);
     102                    } else {
     103                        img.setSequence(sequence);
     104                        imagesAdded = true;
     105                        sequence.add(img);
     106                    }
     107                }
     108                manager.imagesAdded = imagesAdded;
     109                layer.data
     110                        .addWithoutUpdate(new ArrayList<MapillaryAbstractImage>(
     111                                finalImages));
     112            }
     113        } catch (IOException e) {
     114            Main.error("Error reading the url " + url
     115                    + " might be a Mapillary problem.");
     116        }
     117    }
    102118
    103                                         else {
    104                                                 img.setSequence(sequence);
    105                                                 imagesAdded = true;
    106                                         }
    107                                 }
    108                                 manager.imagesAdded = imagesAdded;
    109                                 layer.data
    110                                                 .addWithoutUpdate(new ArrayList<MapillaryAbstractImage>(
    111                                                                 finalImages));
    112                                 sequence.add(finalImages);
    113                         }
    114                 } catch (IOException e) {
    115                         Main.error("Error reading the url " + url
    116                                         + " might be a Mapillary problem.");
    117                 }
    118         }
    119 
    120         private boolean isInside(MapillaryAbstractImage image) {
    121                 for (int i = 0; i < bounds.size(); i++) {
    122                         if (bounds.get(i).contains(image.getLatLon()))
    123                                 return true;
    124                 }
    125                 return false;
    126         }
     119    private boolean isInside(MapillaryAbstractImage image) {
     120        for (int i = 0; i < bounds.size(); i++) {
     121            if (bounds.get(i).contains(image.getLatLon()))
     122                return true;
     123        }
     124        return false;
     125    }
    127126}
  • applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryToggleDialog.java

    r31324 r31326  
    4545 */
    4646public class MapillaryToggleDialog extends ToggleDialog implements
    47                 ICachedLoaderListener, MapillaryDataListener {
    48 
    49         public final static String BASE_TITLE = "Mapillary picture";
    50 
    51         public static MapillaryToggleDialog INSTANCE;
    52 
    53         public volatile MapillaryAbstractImage image;
    54 
    55         public final SideButton nextButton = new SideButton(new nextPictureAction());
    56         public final SideButton previousButton = new SideButton(
    57                         new previousPictureAction());
    58         public final SideButton redButton = new SideButton(new redAction());
    59         public final SideButton blueButton = new SideButton(new blueAction());
    60 
    61         private JPanel buttonsPanel;
    62 
    63         public MapillaryImageDisplay mapillaryImageDisplay;
    64 
    65         private MapillaryCache imageCache;
    66         private MapillaryCache thumbnailCache;
    67 
    68         public MapillaryToggleDialog() {
    69                 super(tr(BASE_TITLE), "mapillary.png", tr("Open Mapillary window"),
    70                                 Shortcut.registerShortcut(tr("Mapillary dialog"),
    71                                                 tr("Open Mapillary main dialog"), KeyEvent.VK_M,
    72                                                 Shortcut.NONE), 200, false,
    73                                 MapillaryPreferenceSetting.class);
    74                 MapillaryData.getInstance().addListener(this);
    75                 addShortcuts();
    76                 mapillaryImageDisplay = new MapillaryImageDisplay();
    77 
    78                 blueButton.setForeground(Color.BLUE);
    79                 redButton.setForeground(Color.RED);
    80 
    81                 createLayout(
    82                                 mapillaryImageDisplay,
    83                                 Arrays.asList(new SideButton[] { blueButton, previousButton,
    84                                                 nextButton, redButton }),
    85                                 Main.pref.getBoolean("mapillary.reverse-buttons"));
    86                 disableAllButtons();
    87 
    88         }
    89 
    90         /**
    91          * Adds the shortcuts to the buttons.
    92          */
    93         private void addShortcuts() {
    94                 nextButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    95                                 KeyStroke.getKeyStroke("PAGE_DOWN"), "next");
    96                 nextButton.getActionMap().put("next", new nextPictureAction());
    97                 previousButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    98                                 KeyStroke.getKeyStroke("PAGE_UP"), "previous");
    99                 previousButton.getActionMap().put("previous",
    100                                 new previousPictureAction());
    101                 blueButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    102                                 KeyStroke.getKeyStroke("control PAGE_UP"), "blue");
    103                 blueButton.getActionMap().put("blue", new blueAction());
    104                 redButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    105                                 KeyStroke.getKeyStroke("control PAGE_DOWN"), "red");
    106                 redButton.getActionMap().put("red", new redAction());
    107         }
    108 
    109         public static MapillaryToggleDialog getInstance() {
    110                 if (INSTANCE == null)
    111                         INSTANCE = new MapillaryToggleDialog();
    112                 return INSTANCE;
    113         }
    114 
    115         public static void destroyInstance() {
    116                 INSTANCE = null;
    117         }
    118 
    119         /**
    120          * Downloads the image of the selected MapillaryImage and sets in the
    121          * MapillaryImageDisplay object.
    122          */
    123         public synchronized void updateImage() {
    124                 if (!SwingUtilities.isEventDispatchThread()) {
    125                         SwingUtilities.invokeLater(new Runnable() {
    126                                 @Override
    127                                 public void run() {
    128                                         updateImage();
    129                                 }
    130                         });
    131                 } else {
    132                         if (MapillaryLayer.INSTANCE == null) {
    133                                 return;
    134                         }
    135                         if (this.image == null) {
    136                                 mapillaryImageDisplay.setImage(null);
    137                                 setTitle(tr(BASE_TITLE));
    138                                 disableAllButtons();
    139                                 return;
    140                         }
    141                         if (image instanceof MapillaryImage) {
    142                                 mapillaryImageDisplay.hyperlink.setVisible(true);
    143                                 MapillaryImage mapillaryImage = (MapillaryImage) this.image;
    144                                 updateTitle();
    145                                 // Enables/disables next/previous buttons
    146                                 this.nextButton.setEnabled(false);
    147                                 this.previousButton.setEnabled(false);
    148                                 if (((MapillaryImage) image).getSequence() != null) {
    149                                         MapillaryImage tempImage = (MapillaryImage) image;
    150                                         while (tempImage.next() != null) {
    151                                                 tempImage = tempImage.next();
    152                                                 if (tempImage.isVisible()) {
    153                                                         this.nextButton.setEnabled(true);
    154                                                         break;
    155                                                 }
    156                                         }
    157                                 }
    158                                 if (((MapillaryImage) image).getSequence() != null) {
    159                                         MapillaryImage tempImage = (MapillaryImage) image;
    160                                         while (tempImage.previous() != null) {
    161                                                 tempImage = tempImage.previous();
    162                                                 if (tempImage.isVisible()) {
    163                                                         this.previousButton.setEnabled(true);
    164                                                         break;
    165                                                 }
    166                                         }
    167                                 }
    168 
    169                                 mapillaryImageDisplay.hyperlink.setURL(mapillaryImage.getKey());
    170                                 // Downloads the thumbnail.
    171                                 this.mapillaryImageDisplay.setImage(null);
    172                                 if (thumbnailCache != null)
    173                                         thumbnailCache.cancelOutstandingTasks();
    174                                 thumbnailCache = new MapillaryCache(mapillaryImage.getKey(),
    175                                                 MapillaryCache.Type.THUMBNAIL);
    176                                 thumbnailCache.submit(this, false);
    177 
    178                                 // Downloads the full resolution image.
    179                                 if (imageCache != null)
    180                                         imageCache.cancelOutstandingTasks();
    181                                 imageCache = new MapillaryCache(mapillaryImage.getKey(),
    182                                                 MapillaryCache.Type.FULL_IMAGE);
    183                                 imageCache.submit(this, false);
    184                         } else if (image instanceof MapillaryImportedImage) {
    185                                 mapillaryImageDisplay.hyperlink.setVisible(false);
    186                                 this.nextButton.setEnabled(false);
    187                                 this.previousButton.setEnabled(false);
    188                                 MapillaryImportedImage mapillaryImage = (MapillaryImportedImage) this.image;
    189                                 try {
    190                                         mapillaryImageDisplay.setImage(mapillaryImage.getImage());
    191                                 } catch (IOException e) {
    192                                         Main.error(e);
    193                                 }
    194                                 mapillaryImageDisplay.hyperlink.setURL(null);
    195                         }
    196                 }
    197         }
    198 
    199         private void disableAllButtons() {
    200                 nextButton.setEnabled(false);
    201                 previousButton.setEnabled(false);
    202                 blueButton.setEnabled(false);
    203                 redButton.setEnabled(false);
    204                 mapillaryImageDisplay.hyperlink.setVisible(false);
    205         }
    206 
    207         /**
    208          * Sets a new MapillaryImage to be shown.
    209          *
    210          * @param image
    211          */
    212         public synchronized void setImage(MapillaryAbstractImage image) {
    213                 this.image = image;
    214         }
    215 
    216         public synchronized void updateTitle() {
    217                 if (!SwingUtilities.isEventDispatchThread()) {
    218                         SwingUtilities.invokeLater(new Runnable() {
    219                                 @Override
    220                                 public void run() {
    221                                         updateTitle();
    222                                 }
    223                         });
    224                 } else {
    225                         MapillaryImage mapillaryImage = (MapillaryImage) this.image;
    226                         String title = tr(BASE_TITLE);
    227                         if (mapillaryImage.getUser() != null)
    228                                 title += " -- " + mapillaryImage.getUser();
    229                         if (mapillaryImage.getCapturedAt() != 0)
    230                                 title += " -- " + mapillaryImage.getDate();
    231                         setTitle(title);
    232                 }
    233         }
    234 
    235         /**
    236          * Returns the MapillaryImage objects which is being shown.
    237          *
    238          * @return
    239          */
    240         public synchronized MapillaryAbstractImage getImage() {
    241                 return this.image;
    242         }
    243 
    244         /**
    245          * Action class form the next image button.
    246          *
    247          * @author Jorge
    248          *
    249          */
    250         class nextPictureAction extends AbstractAction {
    251                 public nextPictureAction() {
    252                         putValue(NAME, tr("Next picture"));
    253                         putValue(SHORT_DESCRIPTION,
    254                                         tr("Shows the next picture in the sequence"));
    255                 }
    256 
    257                 @Override
    258                 public void actionPerformed(ActionEvent e) {
    259                         if (MapillaryToggleDialog.getInstance().getImage() != null) {
    260                                 MapillaryData.getInstance().selectNext();
    261                         }
    262                 }
    263         }
    264 
    265         /**
    266          * Action class for the previous image button.
    267          *
    268          * @author Jorge
    269          *
    270          */
    271         class previousPictureAction extends AbstractAction {
    272                 public previousPictureAction() {
    273                         putValue(NAME, tr("Previous picture"));
    274                         putValue(SHORT_DESCRIPTION,
    275                                         tr("Shows the previous picture in the sequence"));
    276                 }
    277 
    278                 @Override
    279                 public void actionPerformed(ActionEvent e) {
    280                         if (MapillaryToggleDialog.getInstance().getImage() != null) {
    281                                 MapillaryData.getInstance().selectPrevious();
    282                         }
    283                 }
    284         }
    285 
    286         /**
    287          * Action class to jump to the image following the red line.
    288          *
    289          * @author nokutu
    290          *
    291          */
    292         class redAction extends AbstractAction {
    293                 public redAction() {
    294                         putValue(NAME, tr("Jump to red"));
    295                         putValue(
    296                                         SHORT_DESCRIPTION,
    297                                         tr("Jumps to the picture at the other side of the red line"));
    298                 }
    299 
    300                 @Override
    301                 public void actionPerformed(ActionEvent e) {
    302                         if (MapillaryToggleDialog.getInstance().getImage() != null) {
    303                                 MapillaryData.getInstance().setSelectedImage(
    304                                                 MapillaryLayer.RED, true);
    305                         }
    306                 }
    307         }
    308 
    309         /**
    310          * Action class to jump to the image following the blue line.
    311          *
    312          * @author nokutu
    313          *
    314          */
    315         class blueAction extends AbstractAction {
    316                 public blueAction() {
    317                         putValue(NAME, tr("Jump to blue"));
    318                         putValue(
    319                                         SHORT_DESCRIPTION,
    320                                         tr("Jumps to the picture at the other side of the blue line"));
    321                 }
    322 
    323                 @Override
    324                 public void actionPerformed(ActionEvent e) {
    325                         if (MapillaryToggleDialog.getInstance().getImage() != null) {
    326                                 MapillaryData.getInstance().setSelectedImage(
    327                                                 MapillaryLayer.BLUE, true);
    328                         }
    329                 }
    330         }
    331 
    332         /**
    333          * When the pictures are returned from the cache, they are set in the
    334          * {@link MapillaryImageDisplay} object.
    335          */
    336         @Override
    337         public void loadingFinished(final CacheEntry data,
    338                         final CacheEntryAttributes attributes, final LoadResult result) {
    339                 if (!SwingUtilities.isEventDispatchThread()) {
    340                         SwingUtilities.invokeLater(new Runnable() {
    341                                 @Override
    342                                 public void run() {
    343                                         loadingFinished(data, attributes, result);
    344                                 }
    345                         });
    346                 } else if (data != null && result == LoadResult.SUCCESS) {
    347                         try {
    348                                 BufferedImage img = ImageIO.read(new ByteArrayInputStream(data
    349                                                 .getContent()));
    350                                 if (img == null)
    351                                         return;
    352                                 if (this.mapillaryImageDisplay.getImage() == null)
    353                                         mapillaryImageDisplay.setImage(img);
    354                                 else if (img.getHeight() > this.mapillaryImageDisplay
    355                                                 .getImage().getHeight()) {
    356                                         mapillaryImageDisplay.setImage(img);
    357                                 }
    358                         } catch (IOException e) {
    359                                 Main.error(e);
    360                         }
    361                 }
    362         }
    363 
    364         /**
    365          * Creates the layout of the dialog.
    366          *
    367          * @param data
    368          *            The content of the dialog
    369          * @param buttons
    370          *            The buttons where you can click
    371          * @param reverse
    372          *            {@code true} if the buttons should go at the top;
    373          *            {@code false} otherwise.
    374          */
    375         public void createLayout(Component data, List<SideButton> buttons,
    376                         boolean reverse) {
    377                 this.removeAll();
    378                 JPanel panel = new JPanel();
    379                 panel.setLayout(new BorderLayout());
    380                 panel.add(data, BorderLayout.CENTER);
    381                 if (reverse) {
    382                         buttonsPanel = new JPanel(new GridLayout(1, 1));
    383                         if (!buttons.isEmpty() && buttons.get(0) != null) {
    384                                 final JPanel buttonRowPanel = new JPanel(Main.pref.getBoolean(
    385                                                 "dialog.align.left", false) ? new FlowLayout(
    386                                                 FlowLayout.LEFT) : new GridLayout(1, buttons.size()));
    387                                 buttonsPanel.add(buttonRowPanel);
    388                                 for (SideButton button : buttons)
    389                                         buttonRowPanel.add(button);
    390                         }
    391                         panel.add(buttonsPanel, BorderLayout.NORTH);
    392                         createLayout(panel, true, null);
    393                 } else
    394                         createLayout(panel, true, buttons);
    395                 this.add(titleBar, BorderLayout.NORTH);
    396         }
    397 
    398         @Override
    399         public void selectedImageChanged(MapillaryAbstractImage oldImage,
    400                         MapillaryAbstractImage newImage) {
    401                 setImage(MapillaryData.getInstance().getSelectedImage());
    402                 updateImage();
    403         }
    404 
    405         @Override
    406         public void imagesAdded() {
    407         }
     47        ICachedLoaderListener, MapillaryDataListener {
     48
     49    public final static String BASE_TITLE = "Mapillary picture";
     50
     51    public static MapillaryToggleDialog INSTANCE;
     52
     53    public volatile MapillaryAbstractImage image;
     54
     55    public final SideButton nextButton = new SideButton(new nextPictureAction());
     56    public final SideButton previousButton = new SideButton(
     57            new previousPictureAction());
     58    public final SideButton redButton = new SideButton(new redAction());
     59    public final SideButton blueButton = new SideButton(new blueAction());
     60
     61    private JPanel buttonsPanel;
     62
     63    public MapillaryImageDisplay mapillaryImageDisplay;
     64
     65    private MapillaryCache imageCache;
     66    private MapillaryCache thumbnailCache;
     67
     68    public MapillaryToggleDialog() {
     69        super(tr(BASE_TITLE), "mapillary.png", tr("Open Mapillary window"),
     70                Shortcut.registerShortcut(tr("Mapillary dialog"),
     71                        tr("Open Mapillary main dialog"), KeyEvent.VK_M,
     72                        Shortcut.NONE), 200, false,
     73                MapillaryPreferenceSetting.class);
     74        MapillaryData.getInstance().addListener(this);
     75        addShortcuts();
     76        mapillaryImageDisplay = new MapillaryImageDisplay();
     77
     78        blueButton.setForeground(Color.BLUE);
     79        redButton.setForeground(Color.RED);
     80
     81        createLayout(
     82                mapillaryImageDisplay,
     83                Arrays.asList(new SideButton[] { blueButton, previousButton,
     84                        nextButton, redButton }),
     85                Main.pref.getBoolean("mapillary.reverse-buttons"));
     86        disableAllButtons();
     87
     88    }
     89
     90    /**
     91     * Adds the shortcuts to the buttons.
     92     */
     93    private void addShortcuts() {
     94        nextButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     95                KeyStroke.getKeyStroke("PAGE_DOWN"), "next");
     96        nextButton.getActionMap().put("next", new nextPictureAction());
     97        previousButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     98                KeyStroke.getKeyStroke("PAGE_UP"), "previous");
     99        previousButton.getActionMap().put("previous",
     100                new previousPictureAction());
     101        blueButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     102                KeyStroke.getKeyStroke("control PAGE_UP"), "blue");
     103        blueButton.getActionMap().put("blue", new blueAction());
     104        redButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
     105                KeyStroke.getKeyStroke("control PAGE_DOWN"), "red");
     106        redButton.getActionMap().put("red", new redAction());
     107    }
     108
     109    public static MapillaryToggleDialog getInstance() {
     110        if (INSTANCE == null)
     111            INSTANCE = new MapillaryToggleDialog();
     112        return INSTANCE;
     113    }
     114
     115    public static void destroyInstance() {
     116        INSTANCE = null;
     117    }
     118
     119    /**
     120     * Downloads the image of the selected MapillaryImage and sets in the
     121     * MapillaryImageDisplay object.
     122     */
     123    public synchronized void updateImage() {
     124        if (!SwingUtilities.isEventDispatchThread()) {
     125            SwingUtilities.invokeLater(new Runnable() {
     126                @Override
     127                public void run() {
     128                    updateImage();
     129                }
     130            });
     131        } else {
     132            if (MapillaryLayer.INSTANCE == null) {
     133                return;
     134            }
     135            if (this.image == null) {
     136                mapillaryImageDisplay.setImage(null);
     137                setTitle(tr(BASE_TITLE));
     138                disableAllButtons();
     139                return;
     140            }
     141            if (image instanceof MapillaryImage) {
     142                mapillaryImageDisplay.hyperlink.setVisible(true);
     143                MapillaryImage mapillaryImage = (MapillaryImage) this.image;
     144                updateTitle();
     145                // Enables/disables next/previous buttons
     146                this.nextButton.setEnabled(false);
     147                this.previousButton.setEnabled(false);
     148                if (((MapillaryImage) image).getSequence() != null) {
     149                    MapillaryImage tempImage = (MapillaryImage) image;
     150                    while (tempImage.next() != null) {
     151                        tempImage = tempImage.next();
     152                        if (tempImage.isVisible()) {
     153                            this.nextButton.setEnabled(true);
     154                            break;
     155                        }
     156                    }
     157                }
     158                if (((MapillaryImage) image).getSequence() != null) {
     159                    MapillaryImage tempImage = (MapillaryImage) image;
     160                    while (tempImage.previous() != null) {
     161                        tempImage = tempImage.previous();
     162                        if (tempImage.isVisible()) {
     163                            this.previousButton.setEnabled(true);
     164                            break;
     165                        }
     166                    }
     167                }
     168
     169                mapillaryImageDisplay.hyperlink.setURL(mapillaryImage.getKey());
     170                // Downloads the thumbnail.
     171                this.mapillaryImageDisplay.setImage(null);
     172                if (thumbnailCache != null)
     173                    thumbnailCache.cancelOutstandingTasks();
     174                thumbnailCache = new MapillaryCache(mapillaryImage.getKey(),
     175                        MapillaryCache.Type.THUMBNAIL);
     176                thumbnailCache.submit(this, false);
     177
     178                // Downloads the full resolution image.
     179                if (imageCache != null)
     180                    imageCache.cancelOutstandingTasks();
     181                imageCache = new MapillaryCache(mapillaryImage.getKey(),
     182                        MapillaryCache.Type.FULL_IMAGE);
     183                imageCache.submit(this, false);
     184            } else if (image instanceof MapillaryImportedImage) {
     185                mapillaryImageDisplay.hyperlink.setVisible(false);
     186                this.nextButton.setEnabled(false);
     187                this.previousButton.setEnabled(false);
     188                MapillaryImportedImage mapillaryImage = (MapillaryImportedImage) this.image;
     189                try {
     190                    mapillaryImageDisplay.setImage(mapillaryImage.getImage());
     191                } catch (IOException e) {
     192                    Main.error(e);
     193                }
     194                mapillaryImageDisplay.hyperlink.setURL(null);
     195            }
     196        }
     197    }
     198
     199    private void disableAllButtons() {
     200        nextButton.setEnabled(false);
     201        previousButton.setEnabled(false);
     202        blueButton.setEnabled(false);
     203        redButton.setEnabled(false);
     204        mapillaryImageDisplay.hyperlink.setVisible(false);
     205    }
     206
     207    /**
     208     * Sets a new MapillaryImage to be shown.
     209     *
     210     * @param image
     211     */
     212    public synchronized void setImage(MapillaryAbstractImage image) {
     213        this.image = image;
     214    }
     215
     216    public synchronized void updateTitle() {
     217        if (!SwingUtilities.isEventDispatchThread()) {
     218            SwingUtilities.invokeLater(new Runnable() {
     219                @Override
     220                public void run() {
     221                    updateTitle();
     222                }
     223            });
     224        } else {
     225            if (this.image != null) {
     226                MapillaryImage mapillaryImage = (MapillaryImage) this.image;
     227                String title = tr(BASE_TITLE);
     228                if (mapillaryImage.getUser() != null)
     229                    title += " -- " + mapillaryImage.getUser();
     230                if (mapillaryImage.getCapturedAt() != 0)
     231                    title += " -- " + mapillaryImage.getDate();
     232                setTitle(title);
     233            }
     234        }
     235    }
     236
     237    /**
     238     * Returns the MapillaryImage objects which is being shown.
     239     *
     240     * @return
     241     */
     242    public synchronized MapillaryAbstractImage getImage() {
     243        return this.image;
     244    }
     245
     246    /**
     247     * Action class form the next image button.
     248     *
     249     * @author Jorge
     250     *
     251     */
     252    class nextPictureAction extends AbstractAction {
     253        public nextPictureAction() {
     254            putValue(NAME, tr("Next picture"));
     255            putValue(SHORT_DESCRIPTION,
     256                    tr("Shows the next picture in the sequence"));
     257        }
     258
     259        @Override
     260        public void actionPerformed(ActionEvent e) {
     261            if (MapillaryToggleDialog.getInstance().getImage() != null) {
     262                MapillaryData.getInstance().selectNext();
     263            }
     264        }
     265    }
     266
     267    /**
     268     * Action class for the previous image button.
     269     *
     270     * @author Jorge
     271     *
     272     */
     273    class previousPictureAction extends AbstractAction {
     274        public previousPictureAction() {
     275            putValue(NAME, tr("Previous picture"));
     276            putValue(SHORT_DESCRIPTION,
     277                    tr("Shows the previous picture in the sequence"));
     278        }
     279
     280        @Override
     281        public void actionPerformed(ActionEvent e) {
     282            if (MapillaryToggleDialog.getInstance().getImage() != null) {
     283                MapillaryData.getInstance().selectPrevious();
     284            }
     285        }
     286    }
     287
     288    /**
     289     * Action class to jump to the image following the red line.
     290     *
     291     * @author nokutu
     292     *
     293     */
     294    class redAction extends AbstractAction {
     295        public redAction() {
     296            putValue(NAME, tr("Jump to red"));
     297            putValue(
     298                    SHORT_DESCRIPTION,
     299                    tr("Jumps to the picture at the other side of the red line"));
     300        }
     301
     302        @Override
     303        public void actionPerformed(ActionEvent e) {
     304            if (MapillaryToggleDialog.getInstance().getImage() != null) {
     305                MapillaryData.getInstance().setSelectedImage(
     306                        MapillaryLayer.RED, true);
     307            }
     308        }
     309    }
     310
     311    /**
     312     * Action class to jump to the image following the blue line.
     313     *
     314     * @author nokutu
     315     *
     316     */
     317    class blueAction extends AbstractAction {
     318        public blueAction() {
     319            putValue(NAME, tr("Jump to blue"));
     320            putValue(
     321                    SHORT_DESCRIPTION,
     322                    tr("Jumps to the picture at the other side of the blue line"));
     323        }
     324
     325        @Override
     326        public void actionPerformed(ActionEvent e) {
     327            if (MapillaryToggleDialog.getInstance().getImage() != null) {
     328                MapillaryData.getInstance().setSelectedImage(
     329                        MapillaryLayer.BLUE, true);
     330            }
     331        }
     332    }
     333
     334    /**
     335     * When the pictures are returned from the cache, they are set in the
     336     * {@link MapillaryImageDisplay} object.
     337     */
     338    @Override
     339    public void loadingFinished(final CacheEntry data,
     340            final CacheEntryAttributes attributes, final LoadResult result) {
     341        if (!SwingUtilities.isEventDispatchThread()) {
     342            SwingUtilities.invokeLater(new Runnable() {
     343                @Override
     344                public void run() {
     345                    loadingFinished(data, attributes, result);
     346                }
     347            });
     348        } else if (data != null && result == LoadResult.SUCCESS) {
     349            try {
     350                BufferedImage img = ImageIO.read(new ByteArrayInputStream(data
     351                        .getContent()));
     352                if (img == null)
     353                    return;
     354                if (this.mapillaryImageDisplay.getImage() == null)
     355                    mapillaryImageDisplay.setImage(img);
     356                else if (img.getHeight() > this.mapillaryImageDisplay
     357                        .getImage().getHeight()) {
     358                    mapillaryImageDisplay.setImage(img);
     359                }
     360            } catch (IOException e) {
     361                Main.error(e);
     362            }
     363        }
     364    }
     365
     366    /**
     367     * Creates the layout of the dialog.
     368     *
     369     * @param data
     370     *            The content of the dialog
     371     * @param buttons
     372     *            The buttons where you can click
     373     * @param reverse
     374     *            {@code true} if the buttons should go at the top;
     375     *            {@code false} otherwise.
     376     */
     377    public void createLayout(Component data, List<SideButton> buttons,
     378            boolean reverse) {
     379        this.removeAll();
     380        JPanel panel = new JPanel();
     381        panel.setLayout(new BorderLayout());
     382        panel.add(data, BorderLayout.CENTER);
     383        if (reverse) {
     384            buttonsPanel = new JPanel(new GridLayout(1, 1));
     385            if (!buttons.isEmpty() && buttons.get(0) != null) {
     386                final JPanel buttonRowPanel = new JPanel(Main.pref.getBoolean(
     387                        "dialog.align.left", false) ? new FlowLayout(
     388                        FlowLayout.LEFT) : new GridLayout(1, buttons.size()));
     389                buttonsPanel.add(buttonRowPanel);
     390                for (SideButton button : buttons)
     391                    buttonRowPanel.add(button);
     392            }
     393            panel.add(buttonsPanel, BorderLayout.NORTH);
     394            createLayout(panel, true, null);
     395        } else
     396            createLayout(panel, true, buttons);
     397        this.add(titleBar, BorderLayout.NORTH);
     398    }
     399
     400    @Override
     401    public void selectedImageChanged(MapillaryAbstractImage oldImage,
     402            MapillaryAbstractImage newImage) {
     403        setImage(MapillaryData.getInstance().getSelectedImage());
     404        updateImage();
     405    }
     406
     407    @Override
     408    public void imagesAdded() {
     409    }
    408410}
Note: See TracChangeset for help on using the changeset viewer.