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