001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.relation; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.FlowLayout; 008import java.awt.Rectangle; 009import java.awt.event.ActionEvent; 010import java.awt.event.MouseAdapter; 011import java.awt.event.MouseEvent; 012import java.util.Collections; 013import java.util.List; 014import java.util.stream.Collectors; 015 016import javax.swing.AbstractAction; 017import javax.swing.JButton; 018import javax.swing.JCheckBox; 019import javax.swing.JList; 020import javax.swing.JPanel; 021import javax.swing.JScrollPane; 022import javax.swing.ListSelectionModel; 023import javax.swing.event.ListDataEvent; 024import javax.swing.event.ListDataListener; 025import javax.swing.event.ListSelectionEvent; 026import javax.swing.event.ListSelectionListener; 027 028import org.openstreetmap.josm.actions.downloadtasks.DownloadReferrersTask; 029import org.openstreetmap.josm.data.osm.OsmPrimitive; 030import org.openstreetmap.josm.data.osm.PrimitiveId; 031import org.openstreetmap.josm.data.osm.Relation; 032import org.openstreetmap.josm.gui.MainApplication; 033import org.openstreetmap.josm.gui.PrimitiveRenderer; 034import org.openstreetmap.josm.gui.io.DownloadPrimitivesTask; 035import org.openstreetmap.josm.gui.layer.OsmDataLayer; 036import org.openstreetmap.josm.gui.util.GuiHelper; 037import org.openstreetmap.josm.tools.ImageProvider; 038 039/** 040 * This is browser for a list of relations which refer to another relations. 041 * @since 1806 042 */ 043public class ReferringRelationsBrowser extends JPanel { 044 045 /** the list of relations */ 046 private JList<Relation> referrers; 047 private final ReferringRelationsBrowserModel model; 048 private final transient OsmDataLayer layer; 049 private final JCheckBox cbReadFull = new JCheckBox(tr("including immediate children of parent relations")); 050 private EditAction editAction; 051 052 /** 053 * Constructs a new {@code ReferringRelationsBrowser}. 054 * @param layer OSM data layer 055 * @param model referring relations browser model 056 */ 057 public ReferringRelationsBrowser(OsmDataLayer layer, ReferringRelationsBrowserModel model) { 058 this.model = model; 059 this.layer = layer; 060 build(); 061 } 062 063 /** 064 * build the GUI 065 */ 066 protected void build() { 067 setLayout(new BorderLayout()); 068 referrers = new JList<>(model); 069 referrers.setCellRenderer(new PrimitiveRenderer()); 070 add(new JScrollPane(referrers), BorderLayout.CENTER); 071 referrers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 072 referrers.addMouseListener(new MouseAdapter() { 073 @Override 074 public void mouseClicked(MouseEvent e) { 075 if (e.getClickCount() == 2 076 && !e.isAltDown() && !e.isAltGraphDown() && !e.isControlDown() && !e.isMetaDown() && !e.isShiftDown()) { 077 Rectangle cellBounds = referrers.getCellBounds(referrers.getSelectedIndex(), referrers.getSelectedIndex()); 078 if (cellBounds != null && cellBounds.contains(e.getPoint())) { 079 editAction.actionPerformed(new ActionEvent(e.getSource(), ActionEvent.ACTION_PERFORMED, null)); 080 } 081 } 082 } 083 }); 084 085 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT)); 086 087 ReloadAction reloadAction = new ReloadAction(); 088 referrers.getModel().addListDataListener(reloadAction); 089 pnl.add(new JButton(reloadAction)); 090 pnl.add(cbReadFull); 091 092 editAction = new EditAction(); 093 referrers.getSelectionModel().addListSelectionListener(editAction); 094 pnl.add(new JButton(editAction)); 095 add(pnl, BorderLayout.SOUTH); 096 } 097 098 /** 099 * Initializes the model with layer data. 100 */ 101 public void init() { 102 model.populate(getLayer().data); 103 } 104 105 protected OsmDataLayer getLayer() { 106 return layer; 107 } 108 109 /** 110 * Action for loading the parent relations of a relation 111 * 112 */ 113 class ReloadAction extends AbstractAction implements ListDataListener { 114 ReloadAction() { 115 putValue(SHORT_DESCRIPTION, tr("Load parent relations")); 116 new ImageProvider("dialogs", "refresh").getResource().attachImageIcon(this); 117 putValue(NAME, tr("Reload")); 118 refreshEnabled(); 119 } 120 121 protected void refreshEnabled() { 122 setEnabled(model.canReload()); 123 } 124 125 @Override 126 public void actionPerformed(ActionEvent e) { 127 DownloadReferrersTask task = new DownloadReferrersTask(getLayer(), Collections.singleton(model.getRelation())); 128 MainApplication.worker.submit(task); 129 MainApplication.worker.submit(() -> { 130 if (cbReadFull.isSelected() && !task.getProgressMonitor().isCanceled()) { 131 // download all members of parents 132 List<PrimitiveId> parentsChildren = model.getRelation().referrers(Relation.class) 133 .collect(Collectors.toSet()).stream().flatMap(r -> r.getMemberPrimitives().stream()) 134 .distinct().map(OsmPrimitive::getPrimitiveId).distinct().collect(Collectors.toList()); 135 new DownloadPrimitivesTask(getLayer(), parentsChildren, false).run(); 136 } 137 }); 138 GuiHelper.executeByMainWorkerInEDT(() -> 139 model.populate(model.getRelation().getReferrers().stream() 140 .filter(Relation.class::isInstance) 141 .map(Relation.class::cast) 142 .collect(Collectors.toList())) 143 ); 144 } 145 146 @Override 147 public void contentsChanged(ListDataEvent e) { 148 refreshEnabled(); 149 } 150 151 @Override 152 public void intervalAdded(ListDataEvent e) { 153 refreshEnabled(); 154 } 155 156 @Override 157 public void intervalRemoved(ListDataEvent e) { 158 refreshEnabled(); 159 } 160 } 161 162 /** 163 * Action for editing the currently selected relation 164 * 165 */ 166 class EditAction extends AbstractAction implements ListSelectionListener { 167 EditAction() { 168 putValue(SHORT_DESCRIPTION, tr("Edit the currently selected relation")); 169 new ImageProvider("dialogs", "edit").getResource().attachImageIcon(this); 170 putValue(NAME, tr("Edit")); 171 refreshEnabled(); 172 } 173 174 protected void refreshEnabled() { 175 setEnabled(referrers.getSelectionModel().getMinSelectionIndex() >= 0); 176 } 177 178 @Override 179 public void actionPerformed(ActionEvent e) { 180 run(); 181 } 182 183 public void run() { 184 int idx = referrers.getSelectedIndex(); 185 if (idx < 0) 186 return; 187 Relation r = model.getElementAt(idx); 188 if (r == null) 189 return; 190 RelationEditor editor = RelationEditor.getEditor(getLayer(), r, null); 191 editor.setVisible(true); 192 } 193 194 @Override 195 public void valueChanged(ListSelectionEvent e) { 196 refreshEnabled(); 197 } 198 } 199}