View Javadoc
1   package org.opentrafficsim.editor;
2   
3   import java.io.File;
4   import java.util.Date;
5   import java.util.Optional;
6   
7   import javax.swing.Icon;
8   import javax.swing.JOptionPane;
9   
10  import org.opentrafficsim.animation.data.util.IconUtil;
11  import org.opentrafficsim.swing.gui.OtsSimulationPanel;
12  
13  /**
14   * Object that is part of {@link OtsEditor} and may be used to show dialogs.
15   * <p>
16   * Copyright (c) 2026-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
17   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
18   * </p>
19   * @author Wouter Schakel
20   */
21  public class Dialogs
22  {
23  
24      /** Icon for in question dialog. */
25      private static final Icon QUESTION_ICON = IconUtil.of("Question24.png").get();
26  
27      /** Icon for in description dialog. */
28      private static final Icon DESCRIPTION_ICON = IconUtil.of("Information24.png").get();
29  
30      /** Icon for in warning dialog. */
31      private static final Icon WARNING_ICON = IconUtil.of("Warning24.png").get();;
32  
33      /** Editor. */
34      private final OtsEditor editor;
35  
36      /**
37       * Constructor.
38       * @param editor editor
39       */
40      public Dialogs(final OtsEditor editor)
41      {
42          this.editor = editor;
43      }
44  
45      /**
46       * Requests the user to confirm the deletion of a node. The default button is "Ok". The window popping up is considered
47       * sufficient warning, and in this way a speedy succession of "del" and "enter" may delete a consecutive range of nodes to
48       * be deleted.
49       * @param node node.
50       * @return {@code true} if the user confirms node removal.
51       */
52      public boolean confirmNodeRemoval(final XsdTreeNode node)
53      {
54          return JOptionPane.showConfirmDialog(this.editor, "Remove `" + node + "`?", "Remove?", JOptionPane.OK_CANCEL_OPTION,
55                  JOptionPane.QUESTION_MESSAGE, QUESTION_ICON) == JOptionPane.OK_OPTION;
56      }
57  
58      /**
59       * Shows a dialog in a modal pane to confirm discarding unsaved changes.
60       * @return whether unsaved changes can be discarded.
61       */
62      public boolean confirmDiscardChanges()
63      {
64          return JOptionPane.showConfirmDialog(this.editor, "Discard unsaved changes?", "Discard unsaved changes?",
65                  JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, QUESTION_ICON) == JOptionPane.OK_OPTION;
66      }
67  
68      /**
69       * Shows a dialog in a modal pane to confirm message.
70       * @param message message to be confirmed
71       * @return whether message was confirmed.
72       */
73      public boolean confirmGeneral(final String message)
74      {
75          return JOptionPane.showConfirmDialog(this.editor, message, "Please confirm",
76                  JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, QUESTION_ICON) == JOptionPane.OK_OPTION;
77      }
78  
79      /**
80       * Shows a description in a modal pane.
81       * @param description description.
82       * @param title title of the window, may be {@code null} but typically is the name of the node or attribute
83       */
84      public void showDescription(final String description, final String title)
85      {
86          JOptionPane.showMessageDialog(this.editor, "<html><body><p style='width: 400px;'>" + description + "</p></body></html>",
87                  title == null ? "Description" : OtsSimulationPanel.separatedName(title), JOptionPane.INFORMATION_MESSAGE,
88                  DESCRIPTION_ICON);
89      }
90  
91      /**
92       * Show invalid message.
93       * @param invalidMessage invalid message
94       * @param title title, may be {@code null}
95       */
96      public void showInvalidMessage(final String invalidMessage, final String title)
97      {
98          JOptionPane.showMessageDialog(this.editor, invalidMessage,
99                  title == null ? "Invalid" : OtsSimulationPanel.separatedName(title), JOptionPane.INFORMATION_MESSAGE,
100                 DESCRIPTION_ICON);
101     }
102 
103     /**
104      * Show tree invalid.
105      */
106     public void showInvalidToRunMessage()
107     {
108         JOptionPane.showMessageDialog(this.editor, "The setup is not valid. Make sure no red nodes remain.",
109                 "Setup is not valid", JOptionPane.INFORMATION_MESSAGE, DESCRIPTION_ICON);
110     }
111 
112     /**
113      * Show input parameters have a circular dependency.
114      * @param message exception message
115      */
116     public void showCircularInputParameters(final String message)
117     {
118         JOptionPane.showMessageDialog(this.editor, "Input parameters have a circular dependency: " + message,
119                 "Circular input parameter", JOptionPane.INFORMATION_MESSAGE, WARNING_ICON);
120     }
121 
122     /**
123      * Show message about invalid expression.
124      * @param message exception message
125      */
126     public void showInvalidExpression(final String message)
127     {
128         JOptionPane.showMessageDialog(this.editor, "An expression is not valid: " + message, "Expression not valid",
129                 JOptionPane.INFORMATION_MESSAGE, WARNING_ICON);
130     }
131 
132     /**
133      * Show unable to run.
134      */
135     public void showUnableToRunFromTempFile()
136     {
137         JOptionPane.showMessageDialog(this.editor, "Unable to run, temporary file could not be saved.", "Unable to run",
138                 JOptionPane.INFORMATION_MESSAGE, WARNING_ICON);
139     }
140 
141     /**
142      * Ask to remove temporary file that could not be loaded.
143      * @return whether temporary file may be removed
144      */
145     public boolean confirmRemoveRecentFile()
146     {
147         return JOptionPane.showConfirmDialog(this.editor,
148                 "File could not be loaded. Do you want to remove it from recent files?", "Remove from recent files?",
149                 JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, QUESTION_ICON) == JOptionPane.OK_OPTION;
150     }
151 
152     /**
153      * Ask to clear recent files.
154      * @return whether all recent files may be removed
155      */
156     public boolean confirmClearRecentFiles()
157     {
158         return JOptionPane.showConfirmDialog(this.editor, "Are you sure you want to clear the recent files?",
159                 "Clear recent files?", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
160                 QUESTION_ICON) == JOptionPane.OK_OPTION;
161     }
162 
163     /**
164      * Ask to load auto save file.
165      * @param file file
166      * @return whether to load auto save file, {@code true} means load, {@code false} means ok to delete, empty means do nothing
167      */
168     public Optional<Boolean> confirmLoadAutosaveFile(final File file)
169     {
170         int userInput = JOptionPane.showConfirmDialog(this.editor,
171                 "Autosave file " + file.getName() + " (" + new Date(file.lastModified())
172                         + ") detected. Do you want to load this file? ('No' removes the file)",
173                 "Autosave file detected", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, QUESTION_ICON);
174         return Optional.ofNullable(userInput == JOptionPane.OK_OPTION ? Boolean.TRUE
175                 : (userInput == JOptionPane.NO_OPTION ? Boolean.FALSE : null));
176     }
177 
178     /**
179      * Ask to remove auto save file (which could not be loaded).
180      * @return whether to remove auto save file
181      */
182     public boolean confirmRemoveAutosaveFile()
183     {
184         return JOptionPane.showConfirmDialog(this.editor, "Autosave file could not be loaded. Do you want to remove it?",
185                 "Remove autosave?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
186                 QUESTION_ICON) == JOptionPane.YES_OPTION;
187     }
188 
189     /**
190      * Shows a notification.
191      * @param notification notification, should be short as it is also used as the dialog title
192      */
193     public void notification(final String notification)
194     {
195         notification(notification, notification);
196     }
197 
198     /**
199      * Shows a notification.
200      * @param notification notification
201      * @param title dialog title
202      */
203     public void notification(final String notification, final String title)
204     {
205         JOptionPane.showMessageDialog(this.editor, notification, OtsSimulationPanel.separatedName(title),
206                 JOptionPane.WARNING_MESSAGE, DESCRIPTION_ICON);
207     }
208 
209 }