jsugar

Updated the Javadoc of Window.java, which apparantly contained some errors.

Author
Vngngdn
Date
Aug. 15, 2016, 1:01 p.m.
Hash
6711e1f1aa1921127474200454516dbb375ee7a5
Parent
b61e1d9fb813a885c658c7b03b798223b4078ce1
Modified file
Window.java

Window.java

18 additions and 14 deletions.

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