Ignore:
Timestamp:
2022-03-13T08:07:10+01:00 (3 years ago)
Author:
GerdP
Message:

fix #21825: Delete relations by default when all members are deleted
Patch from taylor.smock:

  • Add table where users can deselect/select relations to delete, when a delete command will remove all members of the relation
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/DeleteFromRelationConfirmationDialog.java

    r17440 r18395  
    99import java.awt.Dimension;
    1010import java.awt.FlowLayout;
     11import java.awt.GridBagLayout;
    1112import java.awt.event.ActionEvent;
    1213import java.awt.event.WindowAdapter;
     
    3536import org.openstreetmap.josm.data.osm.NameFormatter;
    3637import org.openstreetmap.josm.data.osm.OsmPrimitive;
     38import org.openstreetmap.josm.data.osm.Relation;
    3739import org.openstreetmap.josm.data.osm.RelationToChildReference;
    3840import org.openstreetmap.josm.gui.MainApplication;
     
    4345import org.openstreetmap.josm.gui.util.WindowGeometry;
    4446import org.openstreetmap.josm.gui.widgets.HtmlPanel;
     47import org.openstreetmap.josm.tools.GBC;
    4548import org.openstreetmap.josm.tools.I18n;
    4649import org.openstreetmap.josm.tools.ImageProvider;
     50import org.openstreetmap.josm.tools.Pair;
     51import org.openstreetmap.josm.tools.Utils;
    4752
    4853/**
     
    6974    /** the data model */
    7075    private RelationMemberTableModel model;
     76    /** The data model for deleting relations */
     77    private RelationDeleteModel deletedRelationsModel;
     78    /** The table to hide/show if the relations to delete are not empty*/
    7179    private final HtmlPanel htmlPanel = new HtmlPanel();
    7280    private boolean canceled;
     
    7583    protected JPanel buildRelationMemberTablePanel() {
    7684        JTable table = new JTable(model, new RelationMemberTableColumnModel());
    77         JPanel pnl = new JPanel(new BorderLayout());
    78         pnl.add(new JScrollPane(table));
     85        JPanel pnl = new JPanel(new GridBagLayout());
     86        pnl.add(new JScrollPane(table), GBC.eol().fill());
     87        JTable deletedRelationsTable = new JTable(this.deletedRelationsModel, new RelationDeleteTableColumnModel());
     88        JScrollPane deletedRelationsModelTableScrollPane = new JScrollPane(deletedRelationsTable);
     89        this.deletedRelationsModel.addTableModelListener(
     90                e -> deletedRelationsModelTableScrollPane.setVisible(this.deletedRelationsModel.getRowCount() > 0));
     91        // Default to not visible
     92        deletedRelationsModelTableScrollPane.setVisible(false);
     93        pnl.add(deletedRelationsModelTableScrollPane, GBC.eol().fill());
    7994        return pnl;
    8095    }
     
    92107        model = new RelationMemberTableModel();
    93108        model.addTableModelListener(this);
     109        this.deletedRelationsModel = new RelationDeleteModel();
     110        this.deletedRelationsModel.addTableModelListener(this);
    94111        getContentPane().setLayout(new BorderLayout());
    95112        getContentPane().add(htmlPanel, BorderLayout.NORTH);
     
    103120
    104121    protected void updateMessage() {
    105         int numObjectsToDelete = model.getNumObjectsToDelete();
    106         int numParentRelations = model.getNumParentRelations();
     122        int numObjectsToDelete = this.model.getNumObjectsToDelete() + this.deletedRelationsModel.getNumObjectsToDelete();
     123        int numParentRelations = this.model.getNumParentRelations() + this.deletedRelationsModel.getNumParentRelations();
    107124        final String msg1 = trn(
    108125                "Please confirm to remove <strong>{0} object</strong>.",
     
    120137
    121138    protected void updateTitle() {
    122         int numObjectsToDelete = model.getNumObjectsToDelete();
     139        int numObjectsToDelete = this.model.getNumObjectsToDelete() + this.deletedRelationsModel.getNumObjectsToDelete();
    123140        if (numObjectsToDelete > 0) {
    124141            setTitle(trn("Deleting {0} object", "Deleting {0} objects", numObjectsToDelete, numObjectsToDelete));
     
    143160    public RelationMemberTableModel getModel() {
    144161        return model;
     162    }
     163
     164    /**
     165     * Replies the data model used for relations that should probably be deleted.
     166     * @return the data model
     167     * @since 18395
     168     */
     169    public RelationDeleteModel getDeletedRelationsModel() {
     170        return this.deletedRelationsModel;
    145171    }
    146172
     
    174200            }
    175201            model.data.clear();
     202            this.deletedRelationsModel.data.clear();
    176203        }
    177204        super.setVisible(visible);
     
    326353    }
    327354
     355    /**
     356     * The table model which manages relations that will be deleted, if their children are deleted.
     357     * @since 18395
     358     */
     359    public static class RelationDeleteModel extends DefaultTableModel {
     360        private final transient List<Pair<Relation, Boolean>> data = new ArrayList<>();
     361
     362        @Override
     363        public int getRowCount() {
     364            // This is called in the super constructor. Before we have instantiated the list. Removing the null check
     365            // WILL LEAD TO A SILENT NPE!
     366            if (this.data == null) {
     367                return 0;
     368            }
     369            return this.data.size();
     370        }
     371
     372        /**
     373         * Sets the data that should be displayed in the list.
     374         * @param references A list of references to display
     375         */
     376        public void populate(Collection<Pair<Relation, Boolean>> references) {
     377            this.data.clear();
     378            if (references != null) {
     379                this.data.addAll(references);
     380            }
     381            this.data.sort(Comparator.comparing(pair -> pair.a));
     382            fireTableDataChanged();
     383        }
     384
     385        /**
     386         * Gets the list of children that are currently displayed.
     387         * @return The children.
     388         */
     389        public Set<Relation> getObjectsToDelete() {
     390            return this.data.stream().filter(relation -> relation.b).map(relation -> relation.a).collect(Collectors.toSet());
     391        }
     392
     393        /**
     394         * Gets the number of elements {@link #getObjectsToDelete()} would return.
     395         * @return That number.
     396         */
     397        public int getNumObjectsToDelete() {
     398            return getObjectsToDelete().size();
     399        }
     400
     401        /**
     402         * Gets the set of parent relations
     403         * @return All parent relations of the references
     404         */
     405        public Set<OsmPrimitive> getParentRelations() {
     406            return this.data.stream()
     407                    .flatMap(pair -> Utils.filteredCollection(pair.a.getReferrers(), Relation.class).stream())
     408                    .collect(Collectors.toSet());
     409        }
     410
     411        /**
     412         * Gets the number of elements {@link #getParentRelations()} would return.
     413         * @return That number.
     414         */
     415        public int getNumParentRelations() {
     416            return getParentRelations().size();
     417        }
     418
     419        @Override
     420        public Object getValueAt(int rowIndex, int columnIndex) {
     421            if (this.data.isEmpty()) {
     422                return null;
     423            }
     424            Pair<Relation, Boolean> ref = this.data.get(rowIndex);
     425            switch(columnIndex) {
     426            case 0: return ref.a;
     427            case 1: return ref.b;
     428            default:
     429                assert false : "Illegal column index";
     430            }
     431            return null;
     432        }
     433
     434        @Override
     435        public boolean isCellEditable(int row, int column) {
     436            return !this.data.isEmpty() && column == 1;
     437        }
     438
     439        @Override
     440        public void setValueAt(Object aValue, int row, int column) {
     441            if (this.data.size() > row && column == 1 && aValue instanceof Boolean) {
     442                this.data.get(row).b = ((Boolean) aValue);
     443            }
     444        }
     445
     446        @Override
     447        public Class<?> getColumnClass(int columnIndex) {
     448            switch (columnIndex) {
     449            case 0:
     450                return Relation.class;
     451            case 1:
     452                return Boolean.class;
     453            default:
     454                return super.getColumnClass(columnIndex);
     455            }
     456        }
     457    }
     458
     459    private static class RelationDeleteTableColumnModel extends DefaultTableColumnModel {
     460        protected final void createColumns() {
     461            // column 0 - To Delete
     462            TableColumn col = new TableColumn(0);
     463            col.setHeaderValue(tr("Relation"));
     464            col.setResizable(true);
     465            col.setWidth(100);
     466            col.setPreferredWidth(100);
     467            col.setCellRenderer(new PrimitiveRenderer());
     468            addColumn(col);
     469
     470            // column 0 - From Relation
     471            col = new TableColumn(1);
     472            final String toDelete = tr("To delete");
     473            col.setHeaderValue(toDelete);
     474            col.setResizable(true);
     475            col.setPreferredWidth(toDelete.length());
     476            addColumn(col);
     477        }
     478
     479        RelationDeleteTableColumnModel() {
     480            createColumns();
     481        }
     482    }
     483
    328484    class OKAction extends AbstractAction {
    329485        OKAction() {
Note: See TracChangeset for help on using the changeset viewer.