001/* 002 003Copyright (c) 2011-2016 The Regents of the University of California. 004All rights reserved. 005 006Permission is hereby granted, without written agreement and without 007license or royalty fees, to use, copy, modify, and distribute this 008software and its documentation for any purpose, provided that the above 009copyright notice and the following two paragraphs appear in all copies 010of this software. 011 012IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA LIABLE TO ANY PARTY 013FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016SUCH DAMAGE. 017 018THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023ENHANCEMENTS, OR MODIFICATIONS. 024 025PT_COPYRIGHT_VERSION_2 026COPYRIGHTENDKEY 027 */ 028package ptolemy.vergil.basic.layout.kieler; 029 030import java.util.HashSet; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Set; 034 035import ptolemy.data.DoubleToken; 036import ptolemy.data.expr.Parameter; 037import ptolemy.kernel.undo.UndoAction; 038import ptolemy.kernel.undo.UndoStackAttribute; 039import ptolemy.kernel.util.NamedObj; 040import ptolemy.vergil.actor.LayoutHint; 041import ptolemy.vergil.basic.layout.kieler.ApplyLayoutRequest.CurveEntry; 042import ptolemy.vergil.basic.layout.kieler.ApplyLayoutRequest.LocationEntry; 043 044/** 045 * An undo action that is able to revert the changes made by automatic layout, or to 046 * repeat them in the case of redo. 047 * 048 * @author Miro Spoenemann (<a href="mailto:msp@informatik.uni-kiel.de">msp</a>) 049 * @version $Id$ 050 * @since Ptolemy II 10.0 051 * @Pt.ProposedRating Red (msp) 052 * @Pt.AcceptedRating Red (msp) 053 */ 054public class UndoLayoutAction implements UndoAction { 055 056 /** 057 * Create an undo action for automatic layout. 058 * 059 * @param source The source object, which is typically the parent composite entity. 060 */ 061 public UndoLayoutAction(NamedObj source) { 062 this._source = source; 063 } 064 065 /////////////////////////////////////////////////////////////////// 066 //// public methods //// 067 068 /** 069 * Add a connection. 070 * @param container The container in which to add the connection 071 * @param layoutHint to be added. 072 */ 073 public void addConnection(NamedObj container, LayoutHint layoutHint) { 074 _connAddEntries.add(new ConnectionHintEntry(container, layoutHint)); 075 } 076 077 /** 078 * Add a curve to the undo action. The action will set the exit angle to the 079 * value stored in the given curve entry. 080 * 081 * @param entry A curve entry with stored exit value 082 */ 083 public void addCurve(CurveEntry entry) { 084 _curveEntries.add(entry); 085 } 086 087 /** 088 * Add a location to the undo action. The action will set the location to the 089 * coordinates stored in the given location entry. 090 * 091 * @param entry A location entry with all required data 092 */ 093 public void addLocation(LocationEntry entry) { 094 _locationEntries.add(entry); 095 } 096 097 /** 098 * Execute the undo or redo action. This sets all previously configured locations, 099 * removes connection routing hints that are marked for removal, and adds 100 * connection routing hints that are marked for adding. 101 */ 102 @Override 103 public void execute() throws Exception { 104 UndoLayoutAction undoLayoutAction = new UndoLayoutAction(_source); 105 106 // Process layout hints that shall be removed. 107 for (LayoutHint layoutHint : this._connRemoveEntries) { 108 NamedObj container = layoutHint.getContainer(); 109 if (container != null) { 110 layoutHint.setContainer(null); 111 undoLayoutAction._connAddEntries 112 .add(new ConnectionHintEntry(container, layoutHint)); 113 } 114 } 115 116 // Process locations. 117 for (LocationEntry entry : this._locationEntries) { 118 double[] oldLoc = entry._locatable.getLocation(); 119 undoLayoutAction.addLocation( 120 new LocationEntry(entry._locatable, oldLoc[0], oldLoc[1])); 121 entry._locatable.setLocation(new double[] { entry._x, entry._y }); 122 } 123 124 // Process layout hints that shall be added. 125 for (ConnectionHintEntry entry : this._connAddEntries) { 126 entry._layoutHint.setContainer(entry._container); 127 undoLayoutAction.removeConnection(entry._layoutHint); 128 } 129 130 // Process transition curves. 131 for (CurveEntry entry : this._curveEntries) { 132 Parameter exitAngleParam = entry._transition.exitAngle; 133 DoubleToken token = DoubleToken.convert(exitAngleParam.getToken()); 134 undoLayoutAction.addCurve( 135 new CurveEntry(entry._transition, token.doubleValue())); 136 exitAngleParam.setExpression(Double.toString(entry._exitAngle)); 137 } 138 139 UndoStackAttribute undoInfo = UndoStackAttribute.getUndoInfo(_source); 140 undoInfo.push(undoLayoutAction); 141 } 142 143 /** 144 * Mark the given connection routing hint for removal. The action will remove 145 * the layout hint from its containing relation. 146 * 147 * @param layoutHint A connection routing hint contained in a relation 148 */ 149 public void removeConnection(LayoutHint layoutHint) { 150 _connRemoveEntries.add(layoutHint); 151 } 152 153 /////////////////////////////////////////////////////////////////// 154 //// private variables //// 155 156 /** The configured locations that will be changed. */ 157 private List<LocationEntry> _locationEntries = new LinkedList<LocationEntry>(); 158 /** The configures curves that will be changed. */ 159 private List<CurveEntry> _curveEntries = new LinkedList<CurveEntry>(); 160 /** Layout hints that should be removed from their containing relations. */ 161 private Set<LayoutHint> _connRemoveEntries = new HashSet<LayoutHint>(); 162 /** Layout hints that should be added to relations. */ 163 private List<ConnectionHintEntry> _connAddEntries = new LinkedList<ConnectionHintEntry>(); 164 /** The source object, which is typically the parent composite entity. */ 165 private NamedObj _source; 166 167 /////////////////////////////////////////////////////////////////// 168 //// inner classes //// 169 170 /** 171 * An entry that contains data for adding a connection routing hint. 172 */ 173 private static class ConnectionHintEntry { 174 NamedObj _container; 175 LayoutHint _layoutHint; 176 177 ConnectionHintEntry(NamedObj container, LayoutHint layoutHint) { 178 this._container = container; 179 this._layoutHint = layoutHint; 180 } 181 } 182 183}