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.event.ActionEvent;
24  import javax.swing.Action;
25  import javax.swing.Icon;
26  import javax.swing.JComponent;
27  import javax.swing.JFrame;
28  import javax.swing.JLabel;
29  import javax.swing.JPasswordField;
30  import javax.swing.JSpinner;
31  import javax.swing.JTextField;
32  import javax.swing.SpinnerNumberModel;
33  import org.xnap.commons.gui.Builder;
34  import org.xnap.commons.gui.action.AbstractXNapAction;
35  import org.xnap.commons.gui.util.GUIHelper;
36  import org.xnap.commons.gui.util.IconHelper;
37  import org.xnap.commons.gui.wizard.WizardDialog;
38  import org.xnap.commons.gui.wizard.WizardPage;
39  import org.xnap.commons.util.PortRange;
40  import org.xnap.commons.util.SystemHelper;
41  import com.jgoodies.forms.builder.DefaultFormBuilder;
42  import com.jgoodies.forms.layout.FormLayout;
43  
44  /**
45   * A dialog for editing of global settings.
46   * 
47   * @author Steffen Pingel
48   */
49  public class SettingsWizard extends WizardDialog implements LocaleChangeListener {
50  
51  	private static final int WIDTH = 500;
52  	
53  	private GeneralPage generalPage;
54  	private NotifyPage notifyPage;
55  	private ProgramsPage programsPage;
56  	private IntroductionPage introPage;
57  	
58  	public SettingsWizard(JFrame owner) {
59  		super(owner);
60  		
61  		introPage = new IntroductionPage();
62  		addPage(introPage, "intro");
63  		
64  		generalPage = new GeneralPage();
65  		addPage(generalPage, "general");
66  		
67  		notifyPage = new NotifyPage();
68  		addPage(notifyPage, "notify");
69  		
70  		programsPage = new ProgramsPage();
71  		addPage(programsPage, "programs");
72  		
73  		updateLabels();
74  		revert();
75  		
76  		pack();
77  	}
78  
79  	private DefaultFormBuilder createForm() {
80  		FormLayout layout = new FormLayout("left:max(20dlu;pref), 3dlu, pref, pref:grow(0.5), pref:grow(0.5)", "");
81  		DefaultFormBuilder builder = new DefaultFormBuilder(layout);
82  		builder.setDefaultDialogBorder();
83  		return builder;
84  	}
85  
86  	public void revert() {
87  		generalPage.revert();
88  		notifyPage.revert();
89  		programsPage.revert();
90  	}
91  
92  	public void updateLabels()
93  	{
94  		setTitle(i18n.tr("JHylaFAX Setup Wizard"));
95  		
96  		introPage.updateLabels();
97  		generalPage.updateLabels();
98  		notifyPage.updateLabels();
99  		programsPage.updateLabels();
100 	}
101 
102 	private class IntroductionPage implements WizardPage {
103 
104 		private DefaultFormBuilder builder;
105 		private JLabel introLabel;
106 
107 		public IntroductionPage() {
108 			builder = createForm();
109 			
110 			introLabel = builder.append("");
111 			builder.nextLine();		
112 		}			
113 
114 		public boolean apply() {
115 			if (!Settings.HAS_SEEN_WIZARD.getValue()) {
116 				JHylaFAX.getInstance().resetAllTables();
117 				Settings.HAS_SEEN_WIZARD.setValue(true);
118 			}
119 			return true;
120 		}
121 
122 		public String getDescription() {
123 			return i18n.tr("Easily setup JHylaFAX in 3 steps.");
124 		}
125 
126 		public Icon getIcon() {
127 			return null;
128 		}
129 
130 		public JComponent getPanel() {
131 			return builder.getPanel();
132 		}
133 
134 		public String getTitle() {
135 			return i18n.tr("JHylaFAX Setup Wizard");
136 		}
137 	
138 		public void updateLabels() {
139 			introLabel.setText(GUIHelper.tt(i18n.tr(
140 					"JHylaFAX is a Java client for the HylaFAX fax server. " +
141 					"It is licensed under the " +
142 					"<b>General Public License (GPL)</b>, see about for details." +
143 					"<p>" + 
144 					"<p>Setup requires three simple steps:" + 
145 					"<ol>" +
146 					"<li>Server connection and authentication" +
147 					"<li>Sender and notifcation" +
148 					"<li>External viewer programs" +
149 					"</ol>" +
150 					"<p>Thank you for using JHylaFAX. "), WIDTH));
151 		}
152 		
153 	}
154 	
155 	private class GeneralPage implements WizardPage {
156 		
157 		private DefaultFormBuilder builder;
158 		private JLabel hostnameLabel;
159 		private JTextField hostnameTextField;
160 		private JLabel passwordLabel;
161 		private JPasswordField passwordTextField;
162 		private JLabel portLabel;
163 		private JSpinner portSpinner;
164 		private SpinnerNumberModel portSpinnerModel;
165 		private JLabel usernameLabel;
166 		private JTextField usernameTextField;
167 		private JLabel hostnameDescriptionLabel;
168 		private JLabel usernameDescriptionLabel;
169 
170 		public GeneralPage() {
171 			builder = createForm();
172 			
173 			hostnameDescriptionLabel = new JLabel();
174 			builder.append(hostnameDescriptionLabel, 5);
175 			builder.nextLine();
176 			
177 			hostnameTextField = new JTextField(Constants.DEFAULT_COLUMNS);
178 			hostnameLabel = builder.append("", hostnameTextField, 3);
179 			builder.nextLine();		
180 			
181 			portSpinnerModel = new SpinnerNumberModel();
182 			portSpinnerModel.setMinimum(PortRange.MIN_PORT);
183 			portSpinnerModel.setMaximum(PortRange.MAX_PORT);
184 			portSpinner = new JSpinner(portSpinnerModel);
185 			portSpinner.setEditor(new JSpinner.NumberEditor(portSpinner, "#"));
186 			portLabel = builder.append("", portSpinner);
187 			builder.nextLine();
188 			
189 			usernameDescriptionLabel = new JLabel();
190 			builder.append(usernameDescriptionLabel, 5);
191 			builder.nextLine();
192 			
193 			usernameTextField = new JTextField(Constants.DEFAULT_COLUMNS);
194 			usernameLabel = builder.append("", usernameTextField, 3);
195 			builder.nextLine();
196 		}
197 
198 		public boolean apply() {
199 			Settings.HOSTNAME.setValue(hostnameTextField.getText());
200 			Settings.PORT.setValue(portSpinnerModel.getNumber().intValue());
201 			Settings.USERNAME.setValue(usernameTextField.getText());
202 			return true;
203 		}
204 
205 		public String getDescription() {
206 			return i18n.tr("The connection to the fax server is configured here.");
207 		}
208 
209 		public Icon getIcon() {
210 			return IconHelper.getTitleIcon("connect_established.png");
211 		}
212 
213 		public JComponent getPanel() {
214 			return builder.getPanel();
215 		}
216 
217 		public String getTitle() {
218 			return i18n.tr("HylaFAX Server Connection");
219 		}
220 
221 		public void revert() {
222 			hostnameTextField.setText(Settings.HOSTNAME.getValue());
223 			portSpinnerModel.setValue(Settings.PORT.getValue());
224 			usernameTextField.setText(Settings.USERNAME.getValue());
225 		}
226 		
227 		public void updateLabels() {
228 			hostnameDescriptionLabel.setText(GUIHelper.tt(i18n.tr("Enter the host and port of your HylaFAX server:"), WIDTH));
229 			hostnameLabel.setText(i18n.tr("Host"));
230 			portLabel.setText(i18n.tr("Port"));
231 			
232 			usernameDescriptionLabel.setText(GUIHelper.tt(i18n.tr("Enter a username that is used to login to the server:"), WIDTH));
233 			usernameLabel.setText(i18n.tr("Username"));
234 		}
235 	}
236 
237 	private class NotifyPage implements WizardPage {
238 
239 		private JTextField fullnameTextField;
240 		private DefaultFormBuilder builder;
241 		private JTextField emailTextField;
242 		private JLabel emailLabel;
243 		private JLabel fullnameLabel;
244 		private JLabel fullnameDescriptionLabel;
245 		private JLabel emailDescriptionLabel;
246 
247 		public NotifyPage() {
248 			builder = createForm();
249 			
250 			fullnameDescriptionLabel = new JLabel();
251 			builder.append(fullnameDescriptionLabel, 5);
252 			builder.nextLine();
253 
254 			fullnameTextField = new JTextField(Constants.DEFAULT_COLUMNS);
255 			fullnameLabel = builder.append("", fullnameTextField, 3);
256 			builder.nextLine();
257 
258 			emailDescriptionLabel = new JLabel();
259 			builder.append(emailDescriptionLabel, 5);
260 			builder.nextLine();
261 			
262 			emailTextField = new JTextField(Constants.DEFAULT_COLUMNS);
263 			emailLabel = builder.append("", emailTextField, 3);
264 			builder.nextLine();
265 			
266 		}
267 		
268 		public void updateLabels() {
269 			fullnameDescriptionLabel.setText(GUIHelper.tt(i18n.tr("Enter a name that is used to identify the sender:"), WIDTH));
270 			fullnameLabel.setText(i18n.tr("Name"));
271 			emailDescriptionLabel.setText(GUIHelper.tt(i18n.tr("Enter an email address to receive notification when a fax has been sent or cancelled:"), WIDTH));
272 			emailLabel.setText(i18n.tr("Email"));
273 		}
274 
275 		public boolean apply() {
276 			Settings.FULLNAME.setValue(fullnameTextField.getText());
277 			Settings.EMAIL.setValue(emailTextField.getText());
278 			return true;
279 		}
280 
281 		public String getDescription() {
282 			return i18n.tr("The sender's name and an email address for notifications are configured here.");
283 		}
284 
285 		public Icon getIcon() {
286 			return IconHelper.getTitleIcon("kontact_mail.png");
287 		}
288 
289 		public JComponent getPanel() {
290 			return builder.getPanel();
291 		}
292 
293 		public String getTitle() {
294 			return i18n.tr("Sender and Notification");
295 		}
296 
297 		public void revert() {
298 			fullnameTextField.setText(Settings.FULLNAME.getValue());
299 			emailTextField.setText(Settings.EMAIL.getValue());
300 		}
301 		
302 	}			
303 
304 	private class ProgramsPage implements WizardPage {
305 
306 		private DefaultFormBuilder builder;
307 		private ExecutableChooserPanel viewerPathFileChooserPanel;
308 		private JLabel viewerPathLabel;
309 		private ExecutableChooserPanel docViewerPathFileChooserPanel;
310 		private JLabel docViewerPathLabel;
311 		private String docViewer;
312 		private String viewer;
313 		private SearchProgramsAction searchProgramsAction;
314 		private JLabel viewerDescriptionLabel;
315 		private JLabel searchDescriptionLabel;
316 		private JLabel docViewerDescriptionLabel;
317 		private JLabel descriptionLabel;
318 
319 		public ProgramsPage() {
320 			builder = createForm();
321 
322 			descriptionLabel = new JLabel();
323 			builder.append(descriptionLabel, 5);
324 			builder.nextLine();
325 
326 			viewerDescriptionLabel = new JLabel();
327 			builder.append(viewerDescriptionLabel, 5);
328 			builder.nextLine();
329 			
330 			viewerPathFileChooserPanel = new ExecutableChooserPanel(Constants.DEFAULT_COLUMNS);
331 			viewerPathFileChooserPanel.setDialogParent(SettingsWizard.this);
332 			viewerPathLabel = builder.append("", viewerPathFileChooserPanel, 3);
333 			builder.nextLine();
334 			
335 			docViewerDescriptionLabel = new JLabel();
336 			builder.append(docViewerDescriptionLabel, 5);
337 			builder.nextLine();
338 			
339 			docViewerPathFileChooserPanel = new ExecutableChooserPanel(Constants.DEFAULT_COLUMNS);
340 			docViewerPathFileChooserPanel.setDialogParent(SettingsWizard.this);
341 			docViewerPathLabel = builder.append("", docViewerPathFileChooserPanel, 3);
342 			builder.nextLine();
343 
344 			searchDescriptionLabel = new JLabel();
345 			builder.append(searchDescriptionLabel, 5);
346 			builder.nextLine();
347 			
348 			builder.append("");
349 			builder.nextLine();
350 			
351 			searchProgramsAction = new SearchProgramsAction();
352 			builder.append(Builder.createButton(searchProgramsAction));
353 			builder.nextLine();
354 		}
355 		
356 		public void revert() {
357 			searchForPrograms();
358 			
359 			if (!"".equals(Settings.VIEWER_PATH.getValue())) {
360 				viewerPathFileChooserPanel.getTextField().setText(Settings.VIEWER_PATH.getValue());
361 			}
362 			else {
363 				viewerPathFileChooserPanel.getTextField().setText(viewer);
364 			}
365 			
366 			if (!"".equals(Settings.DOC_VIEWER_PATH.getValue())) {
367 				docViewerPathFileChooserPanel.getTextField().setText(Settings.DOC_VIEWER_PATH.getValue());
368 			}
369 			else {
370 				docViewerPathFileChooserPanel.getTextField().setText(docViewer);
371 			}
372 		}
373 
374 		private void searchForPrograms() {
375 			if (SystemHelper.IS_WINDOWS) {
376 	            if (SystemHelper.IS_WINDOWS_XP) { 
377 	            	viewer= "rundll32.exe shimgvw.dll,ImageView_Fullscreen $f";
378 	            }
379 	            else {
380 	            	String path = System.getenv("ProgramFiles");
381 	            	viewer = searchExecutable(new String[][] {
382 		        			{ path + "\\Windows NT\\Accessories\\ImageVue", "kodakimg.exe", "$f" },
383 		        	});		
384 	            }
385 	            docViewer = searchExecutable(new String[][] {
386 	        			{ null, "gsview32.exe", "$f" },
387 	            });
388 	            
389 			}
390 			else if (SystemHelper.IS_MACOSX) {
391 				viewer = "open -a Preview.app $f";
392 				docViewer = "open -a Preview.app $f";
393 			}
394 			else {
395 	        	viewer = searchExecutable(new String[][] {
396 	        			{ "/usr/bin", "kfax", "$f" },
397 	        	});
398 	        	docViewer = searchExecutable(new String[][] {
399 	        			{ "/usr/bin", "gv", "$f" },
400 	        			{ "/usr/bin", "kghostview", "$f" },
401 	        	});
402 			}			
403 		}
404 		
405 		private String searchExecutable(String[][] programs) {
406 			return programs[0][1] + " " + programs[0][2];
407 			/*
408 			for (int programIndex = 0; programIndex < programs.length; programIndex++) {
409 				String[] program = programs[programIndex];
410 				if (program[0] != null && new File(program[0], program[1]).exists()) {
411 					return program[0] + File.pathSeparator + program[1] + " " + program[2];
412 				}
413 			}
414 			*/
415 		}
416 
417 		public void updateLabels() {
418 			descriptionLabel.setText(GUIHelper.tt(i18n.tr("JHylaFAX depends on external programs to display received and sent faxes. " +
419 					"You can either enter the path of a program or use Search to let JHylaFAX suggest a program." +
420 					"You may use $f as a placeholder for the filename that is passed as a parameter."), WIDTH));
421 			
422 			viewerDescriptionLabel.setText(GUIHelper.tt(i18n.tr("Enter the path of a programm that can handle TIFF G3 files:"), WIDTH));
423 			viewerPathLabel.setText(i18n.tr("Fax Viewer"));
424 			docViewerDescriptionLabel.setText(GUIHelper.tt(i18n.tr("Enter the path of a programm that can handle PostScript files:"), WIDTH));
425 			docViewerPathLabel.setText(i18n.tr("Document Viewer"));
426 			searchProgramsAction.putValue(Action.NAME, i18n.tr("Search"));
427 		}
428 
429 		public boolean apply()
430 		{
431 			Settings.VIEWER_PATH.setValue(viewerPathFileChooserPanel.getTextField().getText());
432 			Settings.DOC_VIEWER_PATH.setValue(docViewerPathFileChooserPanel.getTextField().getText());
433 
434 			return true;
435 		}
436 
437 		public String getDescription() {
438 			return i18n.tr("Viewer programs are configured here.");
439 		}
440 
441 		public Icon getIcon() {
442 			return IconHelper.getTitleIcon("misc.png");
443 		}
444 
445 		public JComponent getPanel() {
446 			return builder.getPanel();
447 		}
448 
449 		public String getTitle() {
450 			return i18n.tr("External Programs");
451 		}
452 
453 		private class SearchProgramsAction extends AbstractXNapAction { 
454 
455 			public SearchProgramsAction() {
456 				putValue(ICON_FILENAME, "find.png");
457 			}
458 						
459 			public void actionPerformed(ActionEvent e)
460 			{
461 				searchForPrograms();
462 				viewerPathFileChooserPanel.getTextField().setText(viewer);
463 				docViewerPathFileChooserPanel.getTextField().setText(docViewer);
464 			}
465 			
466 		}
467 
468 	}		
469 		
470 
471 }