jsugar

Added a filechooser method, prompting the user with an 'open file' dialog.

Author
Vngngdn
Date
Aug. 10, 2016, 7:53 p.m.
Hash
b61e1d9fb813a885c658c7b03b798223b4078ce1
Parent
7b5e417a3da964d43dbb257f2d53963c18f6368d
Modified file
Window.java

Window.java

31 additions and 1 deletion.

View changes Hide changes
1
1
 * Window.java - Module to create a new window with JSugar.
2
2
 * Copyright © 2016 Maarten "Vngngdn" Vangeneugden
3
3
 * 
4
4
 * This program is free software: you can redistribute it and/or modify
5
5
 * it under the terms of the GNU General Public License as published by
6
6
 * the Free Software Foundation, either version 3 of the License, or
7
7
 * (at your option) any later version.
8
8
 * 
9
9
 * This program is distributed in the hope that it will be useful,
10
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
 * GNU General Public License for more details.
13
13
 * 
14
14
 * You should have received a copy of the GNU General Public License
15
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
16
 */
17
17
18
18
/*
19
19
 * TODO list:
20
20
 * - JSlider (It's the same as the JSpinner, only longer. So an extra.)
21
21
 * - JTable (And a JScrollBar to accompany it)
22
-
 * - JFileChooser (?)
+
22
 * - JFileChooser (?)
23
23
 * DONE list:
24
24
 * - JLabel
25
25
 * - JText
26
26
 * - JButton
27
27
 * - JDialogBoxes (you know, everything dialog related)
28
28
 * - JCheckbox
29
29
 * - JRadioButton (properly grouping them has been taken care of as well)
30
30
 * - JSpinner
31
31
 * - JComboBox
32
32
 * - JList
33
33
 */
34
34
35
35
/**
36
36
 * Window class for the program.
37
37
 *
38
38
 * Window contains the necessary data and methods to present the user with what
39
39
 * he's familiar with as being a "window". To make it functional, the developer
40
40
 * can make use of a series of methods to add components to said window, remove
41
41
 * components, and so on.
42
42
 * Currently, Window also contains methods to show dialogs. This will be cleaned
43
43
 * in the near future.
44
44
 * @author Maarten Vangeneugden
45
45
 */
46
46
import javax.swing.*; // FIXME: Maybe namespacing it to "javax.swing;" is a better idea.
47
47
import java.util.NoSuchElementException;
48
48
import java.lang.reflect.Method;
49
49
+
50
50
51
class Window {
51
52
	private JPanel panel; // The panel that contains all the components.
52
53
	private JFrame frame; // The "window" being presented to the user.
53
54
54
55
	/**
55
56
	 * Constructor of Window.
56
57
	 * By creating a new Window instance, this constructor will automatically
57
58
	 * start the initialization of the GUI. After doing so, the caller can
58
59
	 * start adding components to the window as pleased.
59
60
	 * @param title The title to be shown in the window's title bar.
60
61
	 */
61
62
	public Window() {
62
63
		this.panel = new JPanel();
+
64
		// really.
+
65
		try {
+
66
		UIManager.setLookAndFeel(
+
67
				UIManager.getSystemLookAndFeelClassName());
+
68
		} catch(Exception e) {
+
69
			e.printStackTrace();
+
70
		}
+
71
+
72
		this.panel = new JPanel();
63
73
		// TODO: The current title is "Hello world!" but that will become caller
64
74
		// defined soon.
65
75
		JFrame frame = new JFrame("Hello world!");
66
76
		// Makes it so that if the user clicks the X in the titlebar, the window
67
77
		// closes:
68
78
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
69
79
		//frame.getContentPane().add(lblHelloWorld); // So you use a get() in order to set() data? #JavaWTF
70
80
		frame.setContentPane(this.panel); // Connecting the component panel to the window.
71
81
		// Makes the window fit to the necessary width and height, so it can show all "subcomponents".
72
82
		frame.pack(); 	
73
83
		frame.setVisible(true); // Makes the window visible to the user.
74
84
		this.frame = frame;
75
85
	}
76
86
77
87
	/**
78
88
	 * Resizes the window to fit all components.
79
89
	 * By calling this method, the window will evaluate the currently visible
80
90
	 * components, and resize itself so that all components become properly
81
91
	 * visible.
82
92
	 */
83
93
	private void updateWindow() {
84
94
		this.frame.pack();
85
95
	}
86
96
87
97
	/**
88
98
	 * A series of tests for method and class handling.
89
99
	 * When a caller presents certain methods with data concerning reflection,
90
100
	 * the Java classes you need to use for that are quite opaque, and don't
91
101
	 * offer much safety in any way.
92
102
	 * The solution therefore, is run some validation checks, but these take up
93
103
	 * a decent amount of space in terms of LoC.
94
104
	 * This method takes care of all that. Call this function whenever data
95
105
	 * needs to be validated.
96
106
	 * @param methodName The name of the method, as it is declared in object.
97
107
	 * @param object The class instance in where this method will be called.
98
108
	 * @return The method that could be derived from the supplied data, or null
99
109
	 * if that wasn't possible.
100
110
	 * @throws NullPointerException if either methodName or object are null
101
111
	 * pointers.
102
112
	 * @throws IllegalArgumentException if methodName is empty, or the method
103
113
	 * does not appear to be declared in the given object, or object is not a
104
114
	 * class.
105
115
	 */
106
116
	// All unchecked typecasts are safe, and the use of raw types is taken care
107
117
	// of.
108
118
	@SuppressWarnings({"unchecked","rawtypes"})
109
119
	private Method handleReflectionData(String methodName, Object object) {
110
120
		// Null pointer checking:
111
121
		if (methodName == null || object == null) {
112
122
			throw new NullPointerException("One or more of the given parameters are null pointers.");
113
123
		}
114
124
115
125
		// XXX: Some might say the next line should be in an else{} block. But
116
126
		// Scoping rules require that I'd then have to wrap the rest of the
117
127
		// method in the same else to use it.
118
128
		Class methodClass = object.getClass(); 
119
129
		if (methodName.equals("")) {
120
130
			throw new IllegalArgumentException("The given methodName was empty.");
121
131
		}
122
132
		Method method;
123
133
		try { // First: Look if there's a method without parameters.
124
134
			method = methodClass.getMethod(methodName, null);
125
135
		}
126
136
		catch (NoSuchMethodException exception) {
127
137
			try {
128
138
				// It's possible that the method requires an event parameter, so
129
139
				// check for that as well:
130
140
				Class<?>[] parameters = {java.awt.event.ActionEvent.class};
131
141
				method = methodClass.getMethod(methodName, parameters);
132
142
			}
133
143
			catch (NoSuchMethodException e) {
134
144
				throw new IllegalArgumentException("The given method does not appear in the given class. Be aware that the given method mustn't have any parameters, or only 1 parameter, which has to be of type java.awt.event.ActionEvent.");
135
145
			}
136
146
		}
137
147
		// At this stage, the given data has been validated, and we've been able
138
148
		// to retrieve the method itself.
139
149
		return method;
140
150
	}
141
151
142
152
	/**
143
153
	 * Creates a button in the GUI for interaction.
144
154
	 * This function offers a convenient way to create a button, that can be
145
155
	 * directly interacted with by the user. After creation, the button itself
146
156
	 * is returned to the caller, if he wishes to do something else with it.
147
157
	 * @param text The text that will be displayed in the button.
148
158
	 * @param action The action that will be returned to the action listener.
149
159
	 * @param methodName The name of the method that will be called when an
150
160
	 * action is triggered.
151
161
	 * @param objectInstance The object instance that contains the given method.
152
162
	 * This may only be a null pointer if triggerMethod is not an instance
153
163
	 * method.
154
164
	 * performed. This method may accept an ActionEvent parameter as its only
155
165
	 * parameter, or no parameters at all.
156
166
	 * @throws NullPointerException if triggerMethod is a null pointer, or
157
167
	 * the empty String was given.
158
168
	 * @throws IllegalArgumentException if triggerMethod has more than 1
159
169
	 * parameter, or the 1 required parameter is not of type ActionEvent.
160
170
	 * @return The button that was created.
161
171
	 * @see java.awt.event.ActionEvent
162
172
	 * @see java.lang.reflect.Method.invoke()
163
173
	 */
164
174
	public JButton createButton(String text, String action, String methodName, Object triggerObject) {
165
175
		Method triggerMethod = this.handleReflectionData(methodName, triggerObject);
166
176
167
177
		// For starters, we first assert that the given parameters are valid:
168
178
		if (text == null) {
169
179
			text = "";
170
180
		}
171
181
		if (action == null) {
172
182
			action = "";
173
183
		}
174
184
		
175
185
		// When the method gets here, everything's been validated correctly.
176
186
		JButton button = new JButton(text);
177
187
		button.setActionCommand(action);
178
188
		button.addActionListener(
179
189
				new java.awt.event.ActionListener() {
180
190
					public void actionPerformed(java.awt.event.ActionEvent event) {
181
191
						try {
182
192
							triggerMethod.setAccessible(true);
183
193
							if (triggerMethod.getParameterTypes().length == 0) {
184
194
								// FIXME: Next line throws a warning?
185
195
								triggerMethod.invoke(triggerObject, null);
186
196
							}
187
197
							else {
188
198
								triggerMethod.invoke(triggerObject, new Object[]{event});
189
199
							}
190
200
						}
191
201
						catch (Exception useless) {
192
202
							/*
193
203
							 * XXX: Some info on why I don't just throw said
194
204
							 * Exception to the caller:
195
205
							 * Java has this awful language constraint, which
196
206
							 * forces every damn exception that isn't a subclass
197
207
							 * of RuntimeException, to be declared in the method
198
208
							 * declaration. This tends to infect all underlying
199
209
							 * methods as well, and all that for reasons I can't
200
210
							 * comprehend. In order to keep JSugar a simple and
201
211
							 * clean library, I'll rather just handle it here,
202
212
							 * and throw a RuntimeException with appropriate
203
213
							 * details.
204
214
							 */
205
215
							throw new IllegalArgumentException("triggerMethod is not accessible from this context.");
206
216
						}
207
217
					}
208
218
				});
209
219
		this.addComponent(button);
210
220
		return button;
211
221
	}
212
222
213
223
	/**
214
224
	 * Ask the user for input through a dialog box.
215
225
	 * This method presents the user with an input field, that can accept
216
226
	 * textual input. The method will return the given input after the user's
217
227
	 * clicked a button to send.
218
228
	 * @param text The text/question to be asked to the user.
219
229
	 * @return A String, equal to what the user entered.
220
230
	 * @throws NullPointerException if text is a null pointer.
221
231
	 */
222
232
	public String inputDialog(String text) {
223
233
		if (text == null) {
224
234
			throw new NullPointerException("The given text/question was a null pointer.");
225
235
		}
226
236
		return JOptionPane.showInputDialog(text);
227
237
	}
228
238
229
239
	/**
230
240
	 * Give the user a dialog box.
231
241
	 * This method can be used to provide a simple dialog to the user.
232
242
	 * This will show the user the given question, after which a boolean value
233
243
	 * is returned, holding the choice.
234
244
	 * @param text The text/question to be asked to the user.
235
245
	 * @return True if the user confirms, False if he denies.
236
246
	 * @throws NullPointerException if text is a null pointer.
237
247
	 */
238
248
	public boolean confirmDialog(String text) {
239
249
		if (text == null) {
240
250
			throw new NullPointerException("The given text/question was a null pointer.");
241
251
		}
242
252
		final int ACCEPTED = 0;
243
253
		//final int DENIED = 1; // Not used in the current context.
244
254
		int result = this.choiceDialog(text, new String[]{"Confirm", "Deny"});
245
255
		if (result == ACCEPTED) {
246
256
			return true;
247
257
		}
248
258
		else {
249
259
			return false;
250
260
		}
251
261
	}
252
262
253
263
	/**
254
264
	 * Give the user a choice dialog box.
255
265
	 * This method gives the user a simple dialog with predefined choices.
256
266
	 * These choices are to be provided by the caller in a simple array.
257
267
	 *
258
268
	 * Tip: This method works extremely well with arbitrary created choices.
259
269
	 * That is: if the outcome of the dialog is trivial (e.g. Only 1 choice),
260
270
	 * then that value is immediately returned.
261
271
	 * @param text The text/question to be asked to the user.
262
272
	 * @param choices An array of Strings, containing the choices the user can
263
273
	 * pick.
264
274
	 * @return The index value of the picked choice, or -1 if no choices were
265
275
	 * given.
266
276
	 * @throws NullPointerException if text is a null pointer.
267
277
	 */
268
278
	public int choiceDialog(String text, String[] choices) {
269
279
		if (text == null) {
270
280
			throw new NullPointerException("The given text/question was a null pointer.");
271
281
		}
272
282
		// First: handling the trivial cases:
273
283
		if (choices.length == 0) {
274
284
			return -1;
275
285
		}
276
286
		else if (choices.length == 1) {
277
287
			return 0;
278
288
		}
279
289
		int answer = JOptionPane.CLOSED_OPTION;
280
290
		// The dialog needs to be shown again until the user has made a possible
281
291
		// choice, i.e. Chickening out using the close button is not possible
282
292
		// (Because that returns CLOSED_OPTION).
283
293
		while (answer == JOptionPane.CLOSED_OPTION) {
284
294
				JOptionPane.showOptionDialog(
285
295
					null, // The parent component. May become the panel?
286
296
					text, // The text/question to describe the goal
287
297
					"Dialog", // The text in the title bar
288
298
					JOptionPane.DEFAULT_OPTION, // The kind of available options
289
299
					JOptionPane.QUESTION_MESSAGE, // The type of message
290
300
					null, // The icon to show
291
301
					choices, // The possible choices
292
302
					choices[0] // The standard choice
293
303
					);
294
304
		}
295
305
		return answer;
296
306
	}
297
307
		
298
308
299
309
	/**
300
310
	 * Creates a label in the GUI for interaction.
301
311
	 * This function offers a convenient way to create a label, that can be
302
312
	 * directly interacted with by the user. After creation, the label itself
303
313
	 * is returned to the caller, if he wishes to do something else with it.
304
314
	 * @param text The text that will be displayed in the label.
305
315
	 * @return The label that was created.
306
316
	 */
307
317
	public JLabel createLabel(String text) {
308
318
		JLabel label = new JLabel(text);
309
319
		this.addComponent(label);
310
320
		return label;
311
321
	}
312
322
313
323
	/**
314
324
	 * Adds a checkbox to the window.
315
325
	 * By providing a String, you can use this method to easily
316
326
	 * create a checkbox, and add it to the window. 
317
327
	 */
318
328
	public JCheckBox createCheckbox(String text) {
319
329
		JCheckBox checkbox = new JCheckBox(text);
320
330
		this.addComponent(checkbox);
321
331
		return checkbox;
322
332
	}
323
333
324
334
	/**
325
335
	 * Adds radio buttons to the window.
326
336
	 * Given a list of Strings, this method will create the same amount of radio
327
337
	 * buttons.
328
338
	 *
329
339
	 * The radio buttons will silently be grouped in a ButtonGroup object,
330
340
	 * making them automatically disable each other, so only 1 radio button can
331
341
	 * be enabled. This ButtonGroup is immutable.
332
342
	 *
333
343
	 * If you need a mutable ButtonGroup, create your own, and use the {@link
334
344
	 * #addComponent()} method to add the radio buttons manually.
335
345
	 * @param text An array of Strings. The length of the array will determine
336
346
	 * the amount of radio buttons that will be created.
337
347
	 * @return An array of radio buttons, in the same order as text.
338
348
	 */
339
349
	public JRadioButton[] createRadioButtons(String text[]) {
340
350
		JRadioButton[] radioButtons = new JRadioButton[text.length];
341
351
		ButtonGroup buttonGroup = new ButtonGroup();
342
352
		for (int i=0; i<radioButtons.length; i++) {
343
353
			radioButtons[i].setText(text[i]);
344
354
			buttonGroup.add(radioButtons[i]);
345
355
			this.addComponent(radioButtons[i]);
346
356
		}
347
357
348
358
		assert radioButtons.length == buttonGroup.getButtonCount() : "The amount of radio buttons ("+ radioButtons.length +") differs from the amount of buttons in buttonGroup ("+ buttonGroup.getButtonCount() +").";
349
359
		return radioButtons;
350
360
	}
351
361
352
362
	/**
353
363
	 * Adds a number spinner component to the GUI.
354
364
	 * This method allows the caller to create a so-called "spinner component"
355
365
	 * to the window. This spinner is an input box, in which only integers can
356
366
	 * be put.
357
367
	 *
358
368
	 * The caller can set a range, a start value, and a step size.
359
369
	 *
360
370
	 * The spinner created with this method may modify itself based on the
361
371
	 * parameters.
362
372
	 * For example: If the minimum and maximum value are equal, the spinner will
363
373
	 * be disabled.
364
374
	 *
365
375
	 * @param minimum The minimum value that can be selected.
366
376
	 * @param maximum The maximum value that can be selected.
367
377
	 * @param start The value that will initially be shown in the component.
368
378
	 * @param stepSize The step size when the user increases/decreases the
369
379
	 * value.
370
380
	 * @throws IllegalArgumentException if minimum is larger than maximum, 
371
381
	 * start is not in the range of the selectable values, or stepsize is not a
372
382
	 * natural number.
373
383
	 * @return The JSpinner that was added to the window.
374
384
	 */
375
385
	public JSpinner createSpinner(int minimum, int maximum, int start, int stepSize) {
376
386
		// As usual, we begin with checking the contract:
377
387
		if(minimum > maximum) {
378
388
			throw new IllegalArgumentException("The minimum value ("+ minimum +") was larger than the maximum value ("+ maximum +")");
379
389
		}
380
390
		// The "start ∉ [minimum, maximum]" is done by the SpinnerNumberModel
381
391
		// constructor, which will be constructed later.
382
392
		if(stepSize <= 0) { // stepSize ∉ ℕ¹ (In Belgium: ℕ₀)
383
393
			throw new IllegalArgumentException("The stepSize ("+ stepSize +") is not a natural number (excluding 0).");
384
394
		}
385
395
		// If the contract is valid, we can begin:
386
396
		/*
387
397
		 * I'd like to interject here, because this is a nice example of why
388
398
		 * JSugar was a good idea:
389
399
		 * If you want a spinner, you'll typically want an integer spinner. But
390
400
		 * in Swing, when you create a JSpinner, it creates a JSpinner, with a
391
401
		 * predefined 'SpinnerNumberModel' attached to it.
392
402
		 * It's this model you then have to extract from the created spinner, on
393
403
		 * which you need to apply the configuration.
394
404
		 * What you actually have to do, is create a SpinnerNumberModel
395
405
		 * yourself, put your settings on that, and then, create a JSpinner to
396
406
		 * which you give that SpinnerNumberModel.
397
407
		 * In essence: The entire Java framework is shit.
398
408
		 */
399
409
		SpinnerNumberModel spinnerSettings = new SpinnerNumberModel(
400
410
				start,
401
411
				minimum,
402
412
				maximum,
403
413
				stepSize
404
414
				);
405
415
		JSpinner spinner = new JSpinner(spinnerSettings);
406
416
		if(minimum == maximum) { // Trivial value is set already, --> disable.
407
417
			spinner.setEnabled(false);
408
418
		}
409
419
		this.addComponent(spinner);
410
420
		return spinner;
411
421
	}
412
422
413
423
	/**
414
424
	 * Adds a number spinner component to the GUI.
415
425
	 * This method allows the caller to create a so-called "spinner component"
416
426
	 * to the window. This spinner is an input box, in which only integers can
417
427
	 * be put.
418
428
	 * 
419
429
	 * Tip: This method is a convenience method, and works extremely well with
420
430
	 * arbitrary data.
421
431
	 * For example: The start value is automatically set to the minimal possible
422
432
	 * value, and the step size defaults to 1.
423
433
	 * If the minimum and maximum are equal, the component will be disabled, and
424
434
	 * thus, be locked on the only (trivially) possible value.
425
435
	 * If minimum is larger than maximum, the method will notify you of this,
426
436
	 * but also swap the values. So you can rest assured that the spinner will
427
437
	 * handle errors, but also, inform you about it.
428
438
	 * @param minimum The minimum value that can be selected.
429
439
	 * @param maximum The maximum value that can be selected.
430
440
	 * @return The JSpinner component that was added to the window.
431
441
	 */
432
442
	public JSpinner createSpinner(int minimum, int maximum) {
433
443
		// The disabling of equal values is done in the full createSpinner(), so
434
444
		// this is merely switching values if they need to be swapped.
435
445
		if(minimum > maximum) {
436
446
			System.err.println("minimum ("+ minimum +") was larger than maximum ("+ maximum +").");
437
447
			// FIXME: Consider whether it's appropriate to print a stacktrace
438
448
			// here, which may be convenient for debugging.
439
449
			
440
450
			// XXX: I know you don't need the help variable when swapping
441
451
			// integers, because you can also do basic arithmetics. Change it if
442
452
			// it causes too much eye burn for you.
443
453
			int swapValue = minimum;
444
454
			minimum = maximum;
445
455
			maximum = swapValue;
446
456
		}
447
457
448
458
		// Yeah, these 2 variables make you cringe huh, performance addicts?
449
459
		// Drown me in the tears of your useless performance-related opinions.
450
460
		int startValue = minimum;
451
461
		int stepSize = 1;
452
462
		return this.createSpinner(minimum, maximum, startValue, stepSize);
453
463
	}
454
464
455
465
	/**
456
466
	 * Adds a combobox to the GUI.
457
467
	 * Allows the caller to create a combobox by providing the values that
458
468
	 * should be put in it.
459
469
	 *
460
470
	 * This method can only be used for String values. If that is not what you
461
471
	 * need, consider creating your own combobox and adding it manually. Or, if
462
472
	 * you need a combobox for integers, consider {@link #createSpinner()}.
463
473
	 *
464
474
	 * WARNING: {@see JComboBox#getSelectedItem()} returns an object, not a
465
475
	 * String. You need to manually typecast this. This is a constraint of the
466
476
	 * Swing framework.
467
477
	 * @param items An array of Strings that will be put in the combobox.
468
478
	 * @throws NullPointerException if one of the values in items is a null
469
479
	 * pointer.
470
480
	 * @throws IllegalArgumentException if items is empty.
471
481
	 * @return The JCombobox that was added to the window.
472
482
	 */
473
483
	public JComboBox<String> addComboBox(String[] items) {
474
484
		// Contract validation:
475
485
		if(items.length == 0) {
476
486
			throw new IllegalArgumentException("The given array of items was empty.");
477
487
		}
478
488
		for(String item : items) {
479
489
			if(item == null) {
480
490
				throw new NullPointerException("One of the given Strings is a null pointer.");
481
491
			}
482
492
		}
483
493
		// Contract validated, create the component:
484
494
		JComboBox<String> comboBox = new JComboBox<String>(items);
485
495
		comboBox.setSelectedIndex(0);
486
496
		if(comboBox.getItemCount() == 1) { // Trivial selection
487
497
			comboBox.setEnabled(false);
488
498
		}
489
499
		this.addComponent(comboBox);
490
500
		return comboBox;
491
501
	}
492
502
493
503
	/**
494
504
	 * Creates a list of the given data, and adds it to the GUI.
495
505
	 * This will create a JList component, containing the given data. 
496
506
	 * To jar up your memory: A list in this context, is a component in which
497
507
	 * data of the same type is printed out. The user of said list, can then
498
508
	 * select a subset of these items.
499
509
	 *
500
510
	 * @see JList for a collection of possible operations.
501
511
	 * @param items The String items that will be put in the list.
502
512
	 * @throws NullPointerException if one of the values in items is a null
503
513
	 * pointer.
504
514
	 * @throws IllegalArgumentException if items is empty.
505
515
	 * @return A JList component, that was a added to the GUI.
506
516
	 */
507
517
	public JList createList(String[] items) {
508
518
		// Contract validation:
509
519
		if(items.length == 0) {
510
520
			throw new IllegalArgumentException("The given array of items was empty.");
511
521
		}
512
522
		for(String item : items) {
513
523
			if(item == null) {
514
524
				throw new NullPointerException("One of the given Strings is a null pointer.");
515
525
			}
516
526
		}
517
527
		// Contract validated, create the component:
518
528
		JList list = new JList(items);
519
529
		this.addComponent(list);
520
530
		return list;
521
531
	}
522
532
523
533
	/**
524
534
	 * Adds the given component to the GUI.
525
535
	 * This method allows its caller to give a pre-made component, so that it
526
536
	 * can be added to the GUI. Even though its main use is for the Window class
527
537
	 * itself, the user of JSugar can also use it to create components himself,
528
538
	 * and then add them. As such, this method doesn't provide parameters for
529
539
	 * reflection/action triggering purposes.
530
540
	 * @param component The component to be added to the window.
531
541
	 * @throws NullPointerException if the given component is a null pointer.
532
542
	 */
533
543
	public void addComponent(JComponent component) {
534
544
		int originalSize = this.panel.getComponentCount();
535
545
		this.panel.add(component); // Throws the exception if null.
536
546
		this.updateWindow();
537
547
538
548
		assert originalSize == this.panel.getComponentCount()-1 : "A component was supposed to be added to the window, but the total amount of components was unchanged after the addition.";
539
549
	}
540
550
541
551
	/**
542
552
	 * Removes the given component from the GUI.
543
553
	 * This method allows its caller to remove a component from the GUI.
544
554
	 * @param component The component to be removed.
545
555
	 * @throws NoSuchElementException if the given component does not exist in
546
556
	 * the GUI.
547
557
	 * @throws NullPointerException if the given component is a null pointer.
548
558
	 */
549
559
	public void removeComponent(JComponent component) {
550
560
		int originalSize = this.panel.getComponentCount();
551
561
		this.panel.remove(component);
552
562
		int newSize = this.panel.getComponentCount();
553
563
		if (originalSize != newSize+1) {
554
564
			throw new NoSuchElementException("The given component does not exist in the GUI.");
555
565
		}
556
566
		this.updateWindow();
557
567
	}
558
568
}
+
569
	 * Prompts the user with a file chooser dialog.
+
570
	 * By calling this method, the user will be presented with a file chooser
+
571
	 * dialog, out of which a single file can be selected. If the selected file
+
572
	 * exists, a File object is returned, a null pointer if the user cancelled.
+
573
	 * @return A File object representing the file the user selected, or null
+
574
	 * otherwise.
+
575
	 */
+
576
	public File openFileChooserDialog() {
+
577
		JFileChooser fileDialog = new JFileChooser();
+
578
		fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
+
579
+
580
		int userResponse = fileDialog.showOpenDialog(this.panel);
+
581
		if(userResponse == JFileChooser.APPROVE_OPTION) {
+
582
			return fileDialog.getSelectedFile();
+
583
		}
+
584
		else {
+
585
			return null;
+
586
		}
+
587
	}
+
588
}
559
589