Changeset 19014 in josm


Ignore:
Timestamp:
2024-03-08T10:58:03+01:00 (2 months ago)
Author:
GerdP
Message:

fix #23527: Memory leak in relation editor

  • add new method wouldRelationBeUseful() in IRelationEditorActionAccess which doesn't call the problematic method getChangedRelation() to evaluate whether a relation would be useful if saved.
  • add comments and code in unit test for the method that shows how to handle the result of getChangedRelation() in case it is not needed any longer to avoid the memory leak.
Location:
trunk
Files:
5 edited

Legend:

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

    r18968 r19014  
    5656import org.openstreetmap.josm.data.UndoRedoHandler.CommandQueueListener;
    5757import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
    58 import org.openstreetmap.josm.data.osm.IRelation;
    5958import org.openstreetmap.josm.data.osm.OsmPrimitive;
    6059import org.openstreetmap.josm.data.osm.Relation;
     
    406405     * builds the panel with the OK and the Cancel button
    407406     * @param okAction OK action
     407     * @param deleteAction  Delete action
    408408     * @param cancelAction Cancel action
    409409     *
     
    422422        // Keep users from saving invalid relations -- a relation MUST have at least a tag with the key "type"
    423423        // AND must contain at least one other OSM object.
    424         final TableModelListener listener = l -> updateOkPanel(this.actionAccess.getChangedRelation(), okButton, deleteButton);
     424        final TableModelListener listener = l -> updateOkPanel(okButton, deleteButton);
    425425        listener.tableChanged(null);
    426426        this.memberTableModel.addTableModelListener(listener);
     
    430430
    431431    /**
    432      * Update the OK panel area
    433      * @param newRelation What the new relation would "look" like if it were to be saved now
     432     * Update the OK panel area with a temporary relation that looks if it were to be saved now.
    434433     * @param okButton The OK button
    435434     * @param deleteButton The delete button
    436435     */
    437     private void updateOkPanel(IRelation<?> newRelation, JButton okButton, JButton deleteButton) {
    438         okButton.setVisible(newRelation.isUseful() || this.getRelationSnapshot() == null);
    439         deleteButton.setVisible(!newRelation.isUseful() && this.getRelationSnapshot() != null);
    440         if (this.getRelationSnapshot() == null && !newRelation.isUseful()) {
     436    private void updateOkPanel(JButton okButton, JButton deleteButton) {
     437        boolean useful = this.actionAccess.wouldRelationBeUseful();
     438        okButton.setVisible(useful || this.getRelationSnapshot() == null);
     439        deleteButton.setVisible(!useful && this.getRelationSnapshot() != null);
     440        if (this.getRelationSnapshot() == null && !useful) {
    441441            okButton.setText(tr("Delete"));
    442442        } else {
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java

    r18413 r19014  
    3636    @Override
    3737    public void updateEnabledState() {
    38         setEnabled(this.editorAccess.getChangedRelation().isUseful() && isEditorDirty());
     38        setEnabled(this.editorAccess.wouldRelationBeUseful() && isEditorDirty());
    3939    }
    4040}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java

    r18413 r19014  
    99import javax.swing.RootPaneContainer;
    1010
    11 import org.openstreetmap.josm.data.osm.IRelation;
    1211import org.openstreetmap.josm.data.osm.Relation;
    1312import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     
    4948         && !(snapshot == null && getTagModel().getTags().isEmpty())) {
    5049            //give the user a chance to save the changes
    51             int ret = confirmClosingByCancel(this.editorAccess.getChangedRelation());
     50            int ret = confirmClosingByCancel(this.editorAccess.wouldRelationBeUseful());
    5251            if (ret == 0) { //Yes, save the changes
    5352                //copied from OKAction.run()
     
    6261    }
    6362
    64     protected int confirmClosingByCancel(final IRelation<?> newRelation) {
     63    protected int confirmClosingByCancel(boolean isUseful) {
    6564        ButtonSpec[] options = {
    6665                new ButtonSpec(
     
    8685        // Keep users from saving invalid relations -- a relation MUST have at least a tag with the key "type"
    8786        // AND must contain at least one other OSM object.
    88         options[0].setEnabled(newRelation.isUseful());
     87        options[0].setEnabled(isUseful);
    8988
    9089        return HelpAwareOptionPane.showOptionDialog(
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/actions/IRelationEditorActionAccess.java

    r18584 r19014  
    7272    /**
    7373     * Get the changed relation
    74      * @return The changed relation (note: will not be part of a dataset). This should never be {@code null}.
     74     * @return The changed relation (note: will not be part of a dataset) or the
     75     * value returned by {@code getEditor().getRelation()}. This should never be {@code null}.
     76     * If called for a temporary use of the relation instance, make sure to cleanup a copy to avoid memory leaks, see #23527
    7577     * @since 18413
    7678     */
     
    98100
    99101    /**
     102     * Check if the changed relation would be useful.
     103     * @return true if the saved relation has at least one tag and one member
     104     * @since 19014
     105     */
     106    default boolean wouldRelationBeUseful() {
     107        return (getTagModel().getRowCount() > 0 && getMemberTableModel().getRowCount() > 0);
     108    }
     109
     110    /**
    100111     * Get the text field that is used to edit the role.
    101112     * @return The role text field.
  • trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java

    r18433 r19014  
    1717import org.openstreetmap.josm.data.coor.LatLon;
    1818import org.openstreetmap.josm.data.osm.DataSet;
     19import org.openstreetmap.josm.data.osm.IRelation;
    1920import org.openstreetmap.josm.data.osm.Node;
    2021import org.openstreetmap.josm.data.osm.Relation;
     
    169170        relationEditorAccess.getTagModel().initFromPrimitive(relation);
    170171        relationEditorAccess.getEditor().reloadDataFromRelation();
    171         assertDoesNotThrow(relationEditorAccess::getChangedRelation);
     172
     173        assertDoesNotThrow(() -> {
     174            IRelation<?> tempRelation = relationEditorAccess.getChangedRelation();
     175            if (tempRelation.getDataSet() == null)
     176                tempRelation.setMembers(null); // see #19885
     177        });
    172178    }
    173179}
Note: See TracChangeset for help on using the changeset viewer.