View Javadoc
1   package nl.tudelft.simulation.dsol.swing.introspection.gui;
2   
3   import java.awt.BorderLayout;
4   import java.awt.Dimension;
5   import java.awt.FlowLayout;
6   import java.awt.Frame;
7   import java.awt.Toolkit;
8   import java.awt.Window;
9   import java.awt.event.ActionEvent;
10  import java.awt.event.ActionListener;
11  
12  import javax.swing.JButton;
13  import javax.swing.JDialog;
14  import javax.swing.JPanel;
15  import javax.swing.JScrollPane;
16  import javax.swing.JTable;
17  import javax.swing.ScrollPaneConstants;
18  import javax.swing.WindowConstants;
19  
20  import nl.tudelft.simulation.dsol.swing.introspection.table.DynamicTableModel;
21  import nl.tudelft.simulation.introspection.DelegateIntrospection;
22  
23  /**
24   * A GUI element for presentation and manipulation of an introspected object. The dialog is 'powered' by an instance of {see
25   * ObjectJTable}. The dialog is positioned to a 'parent' window, or displayed centered if no parent window is available.
26   * <p>
27   * Copyright (c) 2002-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
28   * for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL
29   * project is distributed under a three-clause BSD-style license, which can be found at
30   * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">
31   * https://https://simulation.tudelft.nl/dsol/docs/latest/license.html</a>.
32   * </p>
33   * @author <a href="https://www.linkedin.com/in/peterhmjacobs">Peter Jacobs</a>.
34   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>.
35   * @author Niels Lang.
36   * @since 1.5
37   */
38  public class IntrospectionDialog extends JDialog
39  {
40      /** */
41      private static final long serialVersionUID = 20140831L;
42  
43      /** the table, set during initialization. */
44      private JTable table;
45  
46      /** the parent window, set during initialization. */
47      private Window parent;
48  
49      /**
50       * Constructs a new IntrospectionDialog.
51       * @param introspected Object; The introspected object
52       */
53      public IntrospectionDialog(final Object introspected)
54      {
55          this(null, introspected);
56      }
57  
58      /**
59       * Constructs a new IntrospectionDialog.
60       * @param parent Window; The parent window, used for locating the dialog
61       * @param introspected Object; The introspected object
62       */
63      public IntrospectionDialog(final Window parent, final Object introspected)
64      {
65          this(parent, DelegateIntrospection.checkDelegation(introspected).toString(),
66                  new ObjectJTable(new ObjectTableModel(introspected)));
67      }
68  
69      /**
70       * Constructs a new IntrospectionDialog.
71       * @param title String; The title of the frame
72       * @param introspected Object; The introspected object
73       */
74      public IntrospectionDialog(final Object introspected, final String title)
75      {
76          this(null, title, new ObjectJTable(new ObjectTableModel(introspected)));
77      }
78  
79      /**
80       * Constructs a new IntrospectionDialog.
81       * @param title String; The title of the dialog
82       * @param content IntrospectingTableModelInterface; The object table-model containing the data of the introspected object
83       */
84      public IntrospectionDialog(final String title, final IntrospectingTableModelInterface content)
85      {
86          this(null, title, content);
87      }
88  
89      /**
90       * Constructs a new IntrospectionDialog.
91       * @param parent Window; The parent window, used for locating the dialog
92       * @param title String; The title of the dialog
93       * @param content IntrospectingTableModelInterface; The object table-model containing the data of the introspected object
94       */
95      public IntrospectionDialog(final Window parent, final String title, final IntrospectingTableModelInterface content)
96      {
97          this(parent, title, new ObjectJTable(content));
98      }
99  
100     /**
101      * Constructs a new IntrospectionDialog.
102      * @param parent Frame; The parent window, used for locating the dialog
103      * @param title String; The title of the dialog
104      * @param introspected Object; The introspected object
105      */
106     public IntrospectionDialog(final Frame parent, final Object introspected, final String title)
107     {
108         this(parent, title, new ObjectJTable(new ObjectTableModel(introspected)));
109     }
110 
111     /**
112      * Constructs a new IntrospectionDialog.
113      * @param title String; The title of the dialog
114      * @param content JTable; The table displaying the data of the introspected object
115      */
116     public IntrospectionDialog(final String title, final JTable content)
117     {
118         this(null, title, content);
119     }
120 
121     /**
122      * Constructs a new IntrospectionDialog.
123      * @param parent Window; The parent window, used for locating the dialog
124      * @param title String; The title of the dialog
125      * @param content JTable; The table displaying the data of the introspected object
126      */
127     public IntrospectionDialog(final Window parent, final String title, final JTable content)
128     {
129         super();
130         this.parent = parent;
131         this.init(title, content);
132     }
133 
134     /**
135      * initializes the dialog.
136      * @param title String; the title of the dialog
137      * @param newTable JTable; the table to display
138      */
139     private void init(final String title, final JTable newTable)
140     {
141         this.table = newTable;
142         this.setModal(false);
143         this.setTitle(title);
144         this.setAlwaysOnTop(true);
145         this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
146         this.getContentPane().setLayout(new BorderLayout());
147         JScrollPane pane = new JScrollPane(newTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
148                 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
149         this.getContentPane().add(newTable.getTableHeader(), BorderLayout.NORTH);
150         this.getContentPane().add(pane, BorderLayout.CENTER);
151         if (newTable instanceof ObjectJTableInterface)
152         {
153             if (((ObjectJTableInterface) newTable).getIntrospectingTableModel() instanceof DynamicTableModel)
154             {
155                 DynamicTableModel model = (DynamicTableModel) ((ObjectJTableInterface) newTable).getIntrospectingTableModel();
156                 this.getContentPane().add(new ButtonPanel(model, newTable), BorderLayout.SOUTH);
157             }
158         }
159         this.pack();
160         setRelativeLocation();
161         this.setVisible(true);
162     }
163 
164     /**
165      * Reformats this dialog to reflect changes in the table displayed.
166      */
167     public void formatDialog()
168     {
169         // NB PropertyChanges of height are not broadcasted by the dialog!
170         // Therefore, a static check is used instead.
171         Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
172         if (this.table.getPreferredSize().height >= 0.5 * d.height
173                 || this.table.getPreferredSize().height + getLocation().y >= 0.9 * d.height)
174         {
175             return;
176         }
177         this.table.setPreferredScrollableViewportSize(this.table.getPreferredSize());
178         pack();
179     }
180 
181     /**
182      * Initializes the location of this dialog relative to its parent window if any.
183      */
184     public void setRelativeLocation()
185     {
186         setLocationRelativeTo(this.parent);
187     }
188 
189     /**
190      * The ButtonPanel adds functionality for adding and removing rows in a table.
191      */
192     class ButtonPanel extends JPanel
193     {
194         /** */
195         private static final long serialVersionUID = 20140831L;
196 
197         /** model. */
198         private DynamicTableModel model;
199 
200         /** the viewer. */
201         private JTable viewer;
202 
203         /**
204          * Constructs a new ButtonPanel.
205          * @param model DynamicTableModel; the model to control
206          * @param viewer JTable; the viewer to control
207          */
208         ButtonPanel(final DynamicTableModel model, final JTable viewer)
209         {
210             this.model = model;
211             this.viewer = viewer;
212             this.setLayout(new BorderLayout());
213             JPanel buttons = new JPanel();
214             FlowLayout manager = new FlowLayout();
215             manager.setHgap(0);
216             manager.setVgap(0);
217             buttons.setLayout(manager);
218             add(buttons, BorderLayout.CENTER);
219             JButton addButton = new JButton("Add row");
220             JButton delButton = new JButton("Delete rows");
221             if (!model.isRowEditable())
222             {
223                 addButton.setEnabled(false);
224                 delButton.setEnabled(false);
225             }
226             buttons.add(addButton);
227             buttons.add(delButton);
228             addButton.addActionListener(new ActionListener()
229             {
230                 @Override
231                 public void actionPerformed(final ActionEvent e)
232                 {
233                     ButtonPanel.this.addRow();
234                     formatDialog();
235                 }
236             });
237             delButton.addActionListener(new ActionListener()
238             {
239                 @Override
240                 public void actionPerformed(final ActionEvent e)
241                 {
242                     ButtonPanel.this.delRows();
243                     formatDialog();
244                 }
245             });
246         }
247 
248         /**
249          * Adds a row.
250          */
251         protected void addRow()
252         {
253             this.model.createRow();
254         }
255 
256         /**
257          * Deletes the rows currently selected from the table model.
258          */
259         protected void delRows()
260         {
261             this.model.deleteRows(this.viewer.getSelectedRows());
262         }
263     }
264 }