OOP2

Added the files for C3.

Author
Vngngdn
Date
Aug. 16, 2016, 8:50 a.m.
Hash
2ab812b4443d46e4fbcff6d2b90b7b531b058589
Parent
634daebfee59323e78328fef0c3e925bf8a3cc54
Modified files
Challenge 4/Article.java
Challenge 4/ArticleType.java
Challenge 4/Client.java
Challenge 4/Main.java
Challenge 4/Window.java

Challenge 4/Article.java

60 additions and 0 deletions.

View changes Hide changes
+
1
 * @author Maarten Vangeneugden - 1438256
+
2
 */
+
3
public class Article {
+
4
+
5
	private int ID;
+
6
	private String title;
+
7
	private String series;
+
8
	private ArticleType type;
+
9
	private Category category;
+
10
+
11
	public Article(int ID, String title, String series, ArticleType type, Category category) { 
+
12
		this.ID = ID;
+
13
		this.title = title;
+
14
		this.series = series;
+
15
		this.type = type;
+
16
		this.category = category;
+
17
	}
+
18
+
19
	public void setID(int ID) {
+
20
		this.ID = ID;
+
21
	}
+
22
+
23
	public int getID() {	
+
24
		return ID;
+
25
	}
+
26
+
27
	public void setTitle(String title) {
+
28
		this.title = title;
+
29
	}
+
30
+
31
	public String getTitle() {	
+
32
		return title;
+
33
	}
+
34
+
35
	public void setSeries(String series) {
+
36
		this.series = series;
+
37
	}
+
38
+
39
	public Series getSeries() {	
+
40
		return series;
+
41
	}
+
42
+
43
	public void setType(ArticleType type) {
+
44
		this.type = type;
+
45
	}
+
46
+
47
	public ArticleType getType() {	
+
48
		return type;
+
49
	}
+
50
+
51
	public void setCategory(Category category) {
+
52
		this.category = category;
+
53
	}
+
54
+
55
	public Category getCategory() {	
+
56
		return category;
+
57
	}
+
58
+
59
}
+
60

Challenge 4/ArticleType.java

5 additions and 0 deletions.

View changes Hide changes
+
1
	BOOK,
+
2
	CD,
+
3
	DVD
+
4
}
+
5

Challenge 4/Client.java

52 additions and 0 deletions.

View changes Hide changes
+
1
+
2
/**
+
3
 * @author Maarten Vangeneugden - 1438256
+
4
 */
+
5
public class Client {
+
6
+
7
	private int ID;
+
8
	private String name;
+
9
	private String email;
+
10
	private List<String> preferences;
+
11
+
12
	public Client(int ID, String name, String email, List<String> preferences) { 
+
13
		this.ID = ID;
+
14
		this.name = name;
+
15
		this.email = email;
+
16
		this.preferences = preferences;
+
17
	}
+
18
+
19
	public void setID(int ID) {
+
20
		this.ID = ID;
+
21
	}
+
22
+
23
	public int getID() {	
+
24
		return ID;
+
25
	}
+
26
+
27
	public void setName(String name) {
+
28
		this.name = name;
+
29
	}
+
30
+
31
	public String getName() {	
+
32
		return name;
+
33
	}
+
34
+
35
	public void setEmail(String email) {
+
36
		this.email = email;
+
37
	}
+
38
+
39
	public String getEmail() {	
+
40
		return email;
+
41
	}
+
42
+
43
	public void setPreferences(List<String> preferences) {
+
44
		this.preferences = preferences;
+
45
	}
+
46
+
47
	public List<String> getPreferences() {	
+
48
		return preferences;
+
49
	}
+
50
+
51
}
+
52

Challenge 4/Main.java

8 additions and 0 deletions.

View changes Hide changes
+
1
 * @author Maarten Vangeneugden - 1438256
+
2
 */
+
3
public class Main {
+
4
	public static void main(String[] args) {
+
5
		Window gui = new Window("Bibliotheek");
+
6
	}
+
7
}
+
8

Challenge 4/Window.java

593 additions and 0 deletions.

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