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