1   /**
2    * JHylaFax - A java client for HylaFAX.
3    *
4    * Copyright (C) 2005 by Steffen Pingel <steffenp@gmx.de>
5    *
6    * This program is free software; you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation; either version 2 of the License, or
9    * (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19   */
20  package net.sf.jhylafax;
21  
22  import static net.sf.jhylafax.JHylaFAX.i18n;
23  import java.awt.Color;
24  import java.util.Locale;
25  import javax.swing.ButtonGroup;
26  import javax.swing.DefaultComboBoxModel;
27  import javax.swing.DefaultListCellRenderer;
28  import javax.swing.JCheckBox;
29  import javax.swing.JComboBox;
30  import javax.swing.JFrame;
31  import javax.swing.JLabel;
32  import javax.swing.JPanel;
33  import javax.swing.JPasswordField;
34  import javax.swing.JRadioButton;
35  import javax.swing.JSpinner;
36  import javax.swing.JTabbedPane;
37  import javax.swing.JTextField;
38  import javax.swing.SpinnerNumberModel;
39  import org.xnap.commons.gui.DefaultDialog;
40  import org.xnap.commons.gui.FileChooserPanel;
41  import org.xnap.commons.gui.completion.CompletionModeFactory;
42  import org.xnap.commons.gui.completion.CompletionModeFactory.CompletionModeInfo;
43  import org.xnap.commons.gui.settings.SettingComponentMediator;
44  import org.xnap.commons.gui.util.EnableListener;
45  import org.xnap.commons.gui.util.WhatsThis;
46  import org.xnap.commons.util.PortRange;
47  import com.jgoodies.forms.builder.DefaultFormBuilder;
48  import com.jgoodies.forms.layout.FormLayout;
49  
50  /**
51   * A dialog for editing of global settings.
52   * 
53   * @author Steffen Pingel
54   */
55  public class SettingsDialog extends DefaultDialog implements LocaleChangeListener {
56  
57  	private JPanel connectionPanel;
58  	private JLabel hostnameLabel;
59  	private JTextField hostnameTextField;
60  	private JPanel jobPanel;
61  	private JobPanel jobParameterPanel;
62  	private JTabbedPane mainTabbedPane;
63  	private JLabel passwordLabel;
64  	private JTextField passwordTextField;
65  	private JLabel portLabel;
66  	private JSpinner portSpinner;
67  	private JLabel usernameLabel;
68  	private JTextField usernameTextField;
69  	private JLabel languageLabel;
70  	private DefaultComboBoxModel languageModel;
71  	private JCheckBox confirmNonPSCheckBox;
72  	private JCheckBox confirmDeleteCheckBox;
73  	private JRadioButton internalCoverRadionButton;
74  	private JLabel viewerPathLabel;
75  	private JLabel docViewerPathLabel;
76  	private JPanel pathsPanel;
77  	private JPanel monitorPanel;
78  	private JRadioButton externalCoverRadionButton;
79  	private FileChooserPanel externalCoverPathFileChooserPanel;
80  	private ExecutableChooserPanel viewerPathFileChooserPanel;
81  	private ExecutableChooserPanel docViewerPathFileChooserPanel;
82  	private JLabel passwordInfoLabel;
83  	private JCheckBox usePassiveCheckBox;
84  	private JPanel generalPanel;
85  	private SpinnerNumberModel portSpinnerModel;
86  	private DefaultComboBoxModel completionModeModel;
87  	private JLabel completionModeLabel;
88  	private JCheckBox sendCoverAsDocumentCheckBox;
89  	private JCheckBox updateOnStartupCheckBox;
90  	private JCheckBox showPollqCheckBox;
91  	private SettingComponentMediator settingMediator = new SettingComponentMediator();
92  	private JCheckBox adminModeCheckBox;
93  	private JPasswordField adminPasswordTextField;
94  	private JCheckBox autoUpdateCheckBox;
95  	private SpinnerNumberModel autoUpdateIntervalModel;
96  	private JSpinner autoUpdateIntervalSpinner;
97  	private JLabel autoUpdateIntervalLabel;
98  	private JCheckBox monitorPathCheckBox;
99  	private SpinnerNumberModel monitorPathIntervalModel;
100 	private JSpinner monitorPathIntervalSpinner;
101 	private JLabel monitorPathIntervalLabel;
102 	private ExecutableChooserPanel monitorPathFileChooserPanel;
103 	private JLabel monitorPathLabel;
104 	private FileChooserPanel addressBookPathFileChooserPanel;
105 	private JCheckBox customizeAddressBookCheckBox;
106 	
107 	public SettingsDialog(JFrame owner) {
108 		super(owner, BUTTON_OKAY | BUTTON_APPLY | BUTTON_CANCEL | BUTTON_CONTEXT_HELP);
109 		
110 		mainTabbedPane = new JTabbedPane();
111 		setMainComponent(mainTabbedPane);
112 		
113 		initializeConnectionForm();
114 		initializeGeneralForm();
115 		initializeJobForm();
116 		initializePathForm();
117 		initializeMonitorForm();
118 		
119 		updateLabels();
120 		revert();
121 		
122 		pack();
123 	}
124 	
125 	@Override
126 	public boolean apply() {
127 		settingMediator.apply();
128 		
129 		Settings.LOCALE.setValue((Locale)languageModel.getSelectedItem());
130 		Settings.DEFAULT_COMPLETION_MODE.setValue(((CompletionModeInfo)completionModeModel.getSelectedItem()).getClassName());
131 		
132 		jobParameterPanel.applyToSettings();
133 		
134 		Settings.VIEWER_PATH.setValue(viewerPathFileChooserPanel.getTextField().getText());
135 		Settings.DOC_VIEWER_PATH.setValue(docViewerPathFileChooserPanel.getTextField().getText());
136 		Settings.USE_INTERNAL_COVER.setValue(internalCoverRadionButton.isSelected());
137 		Settings.COVER_PATH.setValue(externalCoverPathFileChooserPanel.getTextField().getText());
138 		Settings.MONITOR_PATH_INTERVAL.setValue(monitorPathIntervalModel.getNumber().intValue());
139 		
140 		// XXX this is so wrong
141 		JHylaFAX.getInstance().settingsUpdated();
142 		
143 		return true;
144 	}
145 
146 	private DefaultFormBuilder createForm() {
147 		FormLayout layout = new FormLayout("left:max(40dlu;pref), 3dlu, pref, pref:grow(0.5), pref:grow(0.5)", "");
148 		DefaultFormBuilder builder = new DefaultFormBuilder(layout);
149 		builder.setDefaultDialogBorder();
150 		return builder;
151 	}
152 
153 	public void initializeConnectionForm() {
154 		DefaultFormBuilder builder = createForm();
155 		connectionPanel = builder.getPanel();
156 		mainTabbedPane.add(connectionPanel);
157 		
158 		builder.appendSeparator(i18n.tr("HylaFAX Server"));
159 		
160 		hostnameTextField = new JTextField(Constants.DEFAULT_COLUMNS);
161 		settingMediator.add(Settings.HOSTNAME, hostnameTextField);
162 		hostnameLabel = builder.append("", hostnameTextField, 3);
163 		builder.nextLine();
164 		
165 		portSpinnerModel = new SpinnerNumberModel();
166 		portSpinnerModel.setMinimum(PortRange.MIN_PORT);
167 		portSpinnerModel.setMaximum(PortRange.MAX_PORT);
168 		settingMediator.add(Settings.PORT, portSpinnerModel);
169 		portSpinner = new JSpinner(portSpinnerModel);
170 		portSpinner.setEditor(new JSpinner.NumberEditor(portSpinner, "#"));
171 		portLabel = builder.append("", portSpinner);
172 		builder.nextLine();
173 		
174 		usePassiveCheckBox = new JCheckBox();
175 		settingMediator.add(Settings.USE_PASSIVE, usePassiveCheckBox);
176 		builder.append("", usePassiveCheckBox, 3);
177 		builder.nextLine();
178 
179 		builder.appendSeparator(i18n.tr("Authentication"));
180 		
181 		usernameTextField = new JTextField(Constants.DEFAULT_COLUMNS);
182 		settingMediator.add(Settings.USERNAME, usernameTextField);
183 		usernameLabel = builder.append("", usernameTextField, 3);
184 		builder.nextLine();
185 
186 		passwordInfoLabel = new JLabel();
187 		passwordInfoLabel.setForeground(Color.RED);
188 		builder.append(passwordInfoLabel, 5);
189 		builder.nextLine();
190 
191 		passwordTextField = new JPasswordField(Constants.DEFAULT_COLUMNS);
192 		settingMediator.add(Settings.PASSWORD, passwordTextField);
193 		passwordLabel = builder.append("", passwordTextField, 3);
194 		builder.nextLine();
195 		
196 		adminModeCheckBox = new JCheckBox();
197 		settingMediator.add(Settings.ADMIN_MODE, adminModeCheckBox);		
198 		adminPasswordTextField = new JPasswordField(Constants.DEFAULT_COLUMNS);
199 		settingMediator.add(Settings.ADMIN_PASSWORD, adminPasswordTextField);
200 		builder.append(adminModeCheckBox); builder.append(adminPasswordTextField, 3);
201 		builder.nextLine();
202 
203 		adminModeCheckBox.addItemListener(new EnableListener(adminPasswordTextField));
204 		
205 		builder.appendSeparator(i18n.tr("Status Update"));
206 
207 		updateOnStartupCheckBox = new JCheckBox();
208 		settingMediator.add(Settings.UPDATE_ON_STARTUP, updateOnStartupCheckBox);
209 		builder.append(updateOnStartupCheckBox, 4);
210 		builder.nextLine();
211 
212 		autoUpdateCheckBox = new JCheckBox();
213 		autoUpdateCheckBox.setEnabled(false);
214 		settingMediator.add(Settings.DO_AUTO_UPDATE, autoUpdateCheckBox);
215 		// the auto updater is error prone, therefore it has been disabled
216 		// until fixed
217 		//builder.append(autoUpdateCheckBox, 4);
218 		builder.nextLine();
219 		
220 		autoUpdateIntervalModel = new SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 30);
221 		settingMediator.add(Settings.AUTO_UPDATE_INTERVAL, autoUpdateIntervalModel);
222 		autoUpdateIntervalSpinner = new JSpinner(autoUpdateIntervalModel);
223 		autoUpdateIntervalSpinner.setEditor(new JSpinner.NumberEditor(autoUpdateIntervalSpinner, "# s"));
224 		//autoUpdateIntervalLabel = builder.append("", autoUpdateIntervalSpinner);
225 		autoUpdateIntervalLabel = new JLabel();
226 		builder.nextLine();		
227 
228 		autoUpdateCheckBox.addItemListener(new EnableListener(autoUpdateIntervalSpinner));
229 	}
230 	
231 	public void initializeGeneralForm() {
232 		DefaultFormBuilder builder = createForm();
233 		generalPanel = builder.getPanel();
234 		mainTabbedPane.add(generalPanel);
235 
236 		builder.appendSeparator(i18n.tr("Appearance"));
237 
238 		showPollqCheckBox = new JCheckBox();
239 		settingMediator.add(Settings.SHOW_POLLQ, showPollqCheckBox);
240 		builder.append(showPollqCheckBox, 5);
241 		builder.nextLine();
242 		
243 		languageModel = new DefaultComboBoxModel();
244 		JComboBox lanuageComboBox = new JComboBox(languageModel);
245 		lanuageComboBox.setRenderer(new DefaultListCellRenderer() {
246 			public java.awt.Component getListCellRendererComponent(javax.swing.JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
247 				super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
248 				if (value != null) {
249 					setText(((Locale)value).getDisplayName());
250 				}
251 				return this;
252 			}
253 		});
254 		languageLabel = builder.append("", lanuageComboBox, 2);
255 		builder.nextLine();
256 		
257 		builder.appendSeparator(i18n.tr("Behavior"));
258 		
259 		completionModeModel = new DefaultComboBoxModel();
260 		JComboBox completionModeComboBox = new JComboBox(completionModeModel);
261 		completionModeComboBox.setRenderer(new DefaultListCellRenderer() {
262 			public java.awt.Component getListCellRendererComponent(javax.swing.JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
263 				super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
264 				if (value != null) {
265 					setText(((CompletionModeFactory.CompletionModeInfo)value).getName());
266 				}
267 				return this;
268 			}
269 		});
270 		completionModeLabel = builder.append("", completionModeComboBox, 2);
271 		builder.nextLine();
272 		
273 		builder.appendSeparator(i18n.tr("Confirmations"));
274 		
275 		confirmNonPSCheckBox = new JCheckBox();
276 		settingMediator.add(Settings.CONFIRM_NONPS, confirmNonPSCheckBox);
277 		builder.append(confirmNonPSCheckBox, 5);
278 		builder.nextLine();
279 		
280 		confirmDeleteCheckBox = new JCheckBox();
281 		settingMediator.add(Settings.CONFIRM_DELETE, confirmDeleteCheckBox);
282 		builder.append(confirmDeleteCheckBox, 5);
283 		builder.nextLine();
284 	}
285 	
286 	private void initializeJobForm() {
287 		DefaultFormBuilder builder = createForm();
288 		jobPanel = builder.getPanel();
289 		mainTabbedPane.add(jobPanel);
290 		
291 		jobParameterPanel = new JobPanel(false);
292 		builder.append(jobParameterPanel, 5);
293 	}
294 	
295 	public void initializePathForm() {
296 		DefaultFormBuilder builder = createForm();
297 		pathsPanel = builder.getPanel();
298 		mainTabbedPane.add(pathsPanel);
299 		
300 		builder.appendSeparator(i18n.tr("Programs"));
301 		
302 		viewerPathFileChooserPanel = new ExecutableChooserPanel(Constants.DEFAULT_COLUMNS);
303 		viewerPathFileChooserPanel.setDialogParent(this);
304 		viewerPathLabel = builder.append("", viewerPathFileChooserPanel, 3);
305 		builder.nextLine();
306 		
307 		docViewerPathFileChooserPanel = new ExecutableChooserPanel(Constants.DEFAULT_COLUMNS);
308 		docViewerPathFileChooserPanel.setDialogParent(this);
309 		docViewerPathLabel = builder.append("", docViewerPathFileChooserPanel, 3);
310 		builder.nextLine();
311 		
312 		builder.appendSeparator(i18n.tr("Address Book"));
313 		
314 		customizeAddressBookCheckBox = new JCheckBox();
315 		settingMediator.add(Settings.CUSTOMIZE_ADDRESS_BOOK_FILENAME, customizeAddressBookCheckBox);
316 		builder.append(customizeAddressBookCheckBox, 5);
317 		builder.nextLine();		
318 		
319 		addressBookPathFileChooserPanel = new FileChooserPanel(Constants.DEFAULT_COLUMNS);
320 		settingMediator.add(Settings.ADDRESS_BOOK_FILENAME, addressBookPathFileChooserPanel.getTextField());
321 		addressBookPathFileChooserPanel.setDialogParent(this);
322 		builder.append(addressBookPathFileChooserPanel, 5);
323 		builder.nextLine();
324 		
325 		customizeAddressBookCheckBox.addItemListener(new EnableListener(addressBookPathFileChooserPanel));
326 		
327 		builder.appendSeparator(i18n.tr("Cover"));
328 		
329 		internalCoverRadionButton = new JRadioButton();
330 		internalCoverRadionButton.setSelected(true);
331 		builder.append(internalCoverRadionButton, 5);
332 		builder.nextLine();
333 		
334 		externalCoverRadionButton = new JRadioButton();
335 		externalCoverPathFileChooserPanel = new FileChooserPanel(Constants.DEFAULT_COLUMNS);
336 		externalCoverPathFileChooserPanel.setEnabled(false);
337 		externalCoverPathFileChooserPanel.setDialogParent(this);
338 		builder.append(externalCoverRadionButton, 5);
339 		builder.nextLine();
340 		
341 		externalCoverRadionButton.addItemListener(new EnableListener(externalCoverPathFileChooserPanel));
342 		
343 		builder.append(externalCoverPathFileChooserPanel, 5);
344 		builder.nextLine();
345 		
346 		ButtonGroup buttonGroup = new ButtonGroup();
347 		buttonGroup.add(internalCoverRadionButton);
348 		buttonGroup.add(externalCoverRadionButton);
349 		
350 		sendCoverAsDocumentCheckBox = new JCheckBox();
351 		settingMediator.add(Settings.SEND_COVER_AS_DOCUMENT, sendCoverAsDocumentCheckBox);
352 		builder.append(sendCoverAsDocumentCheckBox, 5);
353 		builder.nextLine();
354 	}
355 	
356 
357 	public void initializeMonitorForm() {
358 		DefaultFormBuilder builder = createForm();
359 		monitorPanel = builder.getPanel();
360 		mainTabbedPane.add(monitorPanel);
361 
362 		monitorPathCheckBox = new JCheckBox();
363 		settingMediator.add(Settings.DO_MONITOR_PATH, monitorPathCheckBox);
364 		builder.append(monitorPathCheckBox, 4);
365 		builder.nextLine();
366 
367 		monitorPathFileChooserPanel = new ExecutableChooserPanel(Constants.DEFAULT_COLUMNS);
368 		monitorPathFileChooserPanel.setDialogParent(this);
369 		settingMediator.add(Settings.MONITOR_PATH, monitorPathFileChooserPanel.getTextField());
370 		monitorPathLabel = builder.append("", monitorPathFileChooserPanel, 3);
371 		builder.nextLine();
372 
373 		monitorPathIntervalModel = new SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 30);
374 		monitorPathIntervalSpinner = new JSpinner(monitorPathIntervalModel);
375 		monitorPathIntervalSpinner.setEditor(new JSpinner.NumberEditor(monitorPathIntervalSpinner, "# s"));
376 		monitorPathIntervalLabel = builder.append("", monitorPathIntervalSpinner);
377 		builder.nextLine();		
378 		
379 		monitorPathCheckBox.addItemListener(new EnableListener(monitorPathFileChooserPanel, monitorPathIntervalSpinner));
380 	}
381 
382 	public void defaults() {
383 		settingMediator.revertToDefaults();
384 		
385 		languageModel.setSelectedItem(Settings.LOCALE.getDefaultValue());
386 		completionModeModel.setSelectedItem(CompletionModeFactory.getCompletionModeInfoByClassName(Settings.DEFAULT_COMPLETION_MODE.getDefaultValue()));
387 		
388 		jobParameterPanel.revertFromDefaultSettings();		
389 		
390 		viewerPathFileChooserPanel.getTextField().setText(Settings.VIEWER_PATH.getDefaultValue());
391 		docViewerPathFileChooserPanel.getTextField().setText(Settings.DOC_VIEWER_PATH.getDefaultValue());
392 		internalCoverRadionButton.setSelected(Settings.USE_INTERNAL_COVER.getDefaultValue());
393 		externalCoverPathFileChooserPanel.getTextField().setText(Settings.COVER_PATH.getDefaultValue());
394 		monitorPathIntervalModel.setValue(Settings.MONITOR_PATH_INTERVAL.getDefaultValue());
395 	}
396 	
397 	public void revert() {
398 		settingMediator.revert();
399 		
400 		languageModel.setSelectedItem(Settings.LOCALE.getValue());
401 		completionModeModel.setSelectedItem(CompletionModeFactory.getCompletionModeInfoByClassName(Settings.DEFAULT_COMPLETION_MODE.getValue()));
402 		
403 		jobParameterPanel.revertFromSettings();
404 		
405 		viewerPathFileChooserPanel.getTextField().setText(Settings.VIEWER_PATH.getValue());
406 		docViewerPathFileChooserPanel.getTextField().setText(Settings.DOC_VIEWER_PATH.getValue());
407 		internalCoverRadionButton.setSelected(Settings.USE_INTERNAL_COVER.getValue());
408 		externalCoverPathFileChooserPanel.getTextField().setText(Settings.COVER_PATH.getValue());
409 		monitorPathIntervalModel.setValue(Settings.MONITOR_PATH_INTERVAL.getValue());
410 	}
411 	
412 	public void updateLabels() {
413 		setTitle(i18n.tr("Settings"));
414 		
415 		mainTabbedPane.setTitleAt(mainTabbedPane.indexOfComponent(connectionPanel), i18n.tr("Connection"));	
416 		hostnameLabel.setText(i18n.tr("Host"));
417 		usePassiveCheckBox.setText(i18n.tr("Passive Transfers (Select If Transfers Timeout)"));
418 		portLabel.setText(i18n.tr("Port"));
419 		usernameLabel.setText(i18n.tr("Username"));
420 		WhatsThis.setText(usernameTextField, i18n.tr("The username that is sent to the server."));
421 		passwordLabel.setText(i18n.tr("Password"));
422 		passwordInfoLabel.setText("Warning: Passwords are saved in plain text! If not entered a prompt will be displayed.");
423 		adminModeCheckBox.setText(i18n.tr("Admin Privileges"));
424 		updateOnStartupCheckBox.setText(i18n.tr("Update Status on Startup"));
425 		autoUpdateCheckBox.setText(i18n.tr("Automatically Update Status"));
426 		autoUpdateIntervalLabel.setText(i18n.tr("Update Interval"));
427 		
428 		mainTabbedPane.setTitleAt(mainTabbedPane.indexOfComponent(generalPanel), i18n.tr("General"));
429 		Object selectedItem = languageModel.getSelectedItem();
430 		languageModel.removeAllElements();
431 		for (Locale locale : JHylaFAX.SUPPORTED_LOCALES) {
432 			languageModel.addElement(locale);
433 		}
434 		languageModel.setSelectedItem(selectedItem);
435 		showPollqCheckBox.setText(i18n.tr("Show Pollable Faxes (Takes Effect after Restart)"));
436 		selectedItem = completionModeModel.getSelectedItem();
437 		completionModeModel.removeAllElements();
438 		for (CompletionModeInfo mode : CompletionModeFactory.getInstalledCompletionModes()) {
439 			completionModeModel.addElement(mode);
440 		}
441 		completionModeModel.setSelectedItem(selectedItem);
442 		languageLabel.setText(i18n.tr("Lanuage"));
443 		completionModeLabel.setText(i18n.tr("Default Text Completion"));
444 		confirmNonPSCheckBox.setText(i18n.tr("Confirm Sending Non-Postscript Documents"));
445 		confirmDeleteCheckBox.setText(i18n.tr("Confirm Delete"));
446 
447 		mainTabbedPane.setTitleAt(mainTabbedPane.indexOfComponent(jobPanel), i18n.tr("Fax"));
448 		jobParameterPanel.updateLabels();
449 		
450 		mainTabbedPane.setTitleAt(mainTabbedPane.indexOfComponent(pathsPanel), i18n.tr("Paths"));
451 		viewerPathLabel.setText(i18n.tr("Fax Viewer"));
452 		docViewerPathLabel.setText(i18n.tr("Document Viewer"));
453 		customizeAddressBookCheckBox.setText(i18n.tr("Use Custom Address Book (Takes Effect after Restart)"));
454 		internalCoverRadionButton.setText(i18n.tr("Use Internal Cover"));
455 		externalCoverRadionButton.setText(i18n.tr("Use Custom PostScript File"));
456 		sendCoverAsDocumentCheckBox.setText(i18n.tr("Save Cover in Document Queue After Sending"));
457 
458 		mainTabbedPane.setTitleAt(mainTabbedPane.indexOfComponent(monitorPanel), i18n.tr("Monitor"));
459 		monitorPathCheckBox.setText(i18n.tr("Monitor File"));
460 		monitorPathLabel.setText(i18n.tr("File"));
461 		monitorPathIntervalLabel.setText(i18n.tr("Monitor Interval"));
462 	}
463 
464 }