1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.jhylafax;
21
22 import static net.sf.jhylafax.JHylaFAX.i18n;
23 import gnu.hylafax.HylaFAXClient;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.io.BufferedInputStream;
27 import java.io.ByteArrayInputStream;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.FileNotFoundException;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.OutputStream;
35 import java.text.SimpleDateFormat;
36 import java.util.ArrayList;
37 import java.util.Date;
38 import java.util.Iterator;
39 import java.util.List;
40 import javax.swing.Action;
41 import javax.swing.JCheckBox;
42 import javax.swing.JFrame;
43 import javax.swing.JLabel;
44 import javax.swing.JOptionPane;
45 import javax.swing.JPanel;
46 import javax.swing.JScrollPane;
47 import javax.swing.JTextArea;
48 import javax.swing.JTextField;
49 import net.sf.jhylafax.fax.FaxCover;
50 import net.sf.jhylafax.fax.FaxJob;
51 import net.sf.jhylafax.fax.HylaFAXClientHelper;
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54 import org.xnap.commons.gui.Builder;
55 import org.xnap.commons.gui.Dialogs;
56 import org.xnap.commons.gui.ErrorDialog;
57 import org.xnap.commons.gui.FileChooserPanel;
58 import org.xnap.commons.gui.action.AbstractXNapAction;
59 import org.xnap.commons.io.Job;
60 import org.xnap.commons.io.ProgressMonitor;
61 import org.xnap.commons.io.SubTaskProgressMonitor;
62 import org.xnap.commons.io.UserAbortException;
63 import com.jgoodies.forms.builder.DefaultFormBuilder;
64 import com.jgoodies.forms.layout.CellConstraints;
65 import com.jgoodies.forms.layout.FormLayout;
66
67
68
69
70
71
72 public class SendDialog extends AbstractFaxDialog {
73
74 private final static Log logger = LogFactory.getLog(AbstractQueuePanel.class);
75
76 private JLabel documentLabel;
77 private JPanel coverPanel;
78 private JTextField coverSenderTextField;
79 private JLabel coverSenderLabel;
80 private JTextField coverRecepientTextField;
81 private JLabel coverRecepientLabel;
82 private JTextField coverSubjectTextField;
83 private JLabel coverSubjectLabel;
84 private JTextArea coverCommentTextArea;
85 private JLabel coverCommentLabel;
86 private JPanel documentPanel;
87 private DefaultFormBuilder documentPanelBuilder;
88 private List<FileChooserPanel> documentFileChooserPanels;
89 private JCheckBox includeCoverCheckBox;
90 private JLabel includeCoverLabel;
91 private JScrollPane coverCommentScrollPane;
92 private PreviewCoverAction previewCoverAction;
93
94 private MoreDocumentsAction moreDocumentsAction;
95
96 private boolean quitAfterSending;
97
98 public SendDialog(JFrame owner) {
99 super(owner);
100
101 moreDocumentsAction = new MoreDocumentsAction();
102 previewCoverAction = new PreviewCoverAction();
103
104 addNumberTextField();
105
106 addDocumentsPanel();
107
108 builder.append("", Builder.createButton(moreDocumentsAction));
109 builder.nextLine();
110
111 addDateControls();
112
113 includeCoverCheckBox = new JCheckBox();
114 includeCoverLabel = builder.append("", includeCoverCheckBox);
115 builder.nextLine();
116
117 initializeCoverPanel();
118 coverPanel.setVisible(false);
119 previewCoverAction.setEnabled(false);
120 includeCoverCheckBox.addActionListener(new ActionListener() {
121 public void actionPerformed(ActionEvent e) {
122 coverPanel.setVisible(includeCoverCheckBox.isSelected());
123 previewCoverAction.setEnabled(includeCoverCheckBox.isSelected());
124 pack();
125 }
126 });
127
128 getButtonPanel().add(Builder.createButton(previewCoverAction), 0);
129
130 FaxJob job = new FaxJob();
131 HylaFAXClientHelper.initializeFromSettings(job);
132 setJob(job);
133
134 updateLabels();
135 pack();
136 }
137
138 private void addDocumentsPanel()
139 {
140 documentFileChooserPanels = new ArrayList<FileChooserPanel>();
141
142 FormLayout layout = new FormLayout("left:max(40dlu;pref), 3dlu, pref:grow", "");
143 documentPanelBuilder = new DefaultFormBuilder(layout);
144 FileChooserPanel documentFileChooserPanel = new MyFileChooserPanel(DEFAULT_COLUMNS);
145 documentFileChooserPanel.getFileChooser().setMultiSelectionEnabled(true);
146 documentFileChooserPanels.add(documentFileChooserPanel);
147 documentLabel = documentPanelBuilder.append("", documentFileChooserPanel);
148
149 this.builder.appendRow(builder.getLineGapSpec());
150 this.builder.nextLine();
151 this.builder.appendRow("fill:pref:grow");
152 this.builder.append(documentPanelBuilder.getPanel(), 6);
153
154 builder.nextLine();
155 }
156
157 private void initializeCoverPanel()
158 {
159 FormLayout layout = new FormLayout("left:max(40dlu;pref), 3dlu, pref:grow", "");
160 DefaultFormBuilder builder = new DefaultFormBuilder(layout);
161 coverPanel = builder.getPanel();
162 this.builder.appendRow(builder.getLineGapSpec());
163 this.builder.nextLine();
164 this.builder.appendRow("fill:pref:grow");
165 this.builder.append(coverPanel, 6);
166
167 coverSenderTextField = new JTextField(DEFAULT_COLUMNS);
168 coverSenderTextField.setText(Settings.FULLNAME.getValue());
169 coverSenderLabel = builder.append("", coverSenderTextField);
170 builder.nextLine();
171
172 coverRecepientTextField = new JTextField(DEFAULT_COLUMNS);
173 coverRecepientLabel = builder.append("", coverRecepientTextField);
174 builder.nextLine();
175
176 coverSubjectTextField = new JTextField(DEFAULT_COLUMNS);
177 coverSubjectLabel = builder.append("", coverSubjectTextField);
178 builder.nextLine();
179
180 coverCommentTextArea= new JTextArea(3, DEFAULT_COLUMNS);
181 coverCommentLabel = builder.append("");
182 builder.appendRow("fill:pref:grow");
183 CellConstraints cc = new CellConstraints();
184 coverCommentScrollPane = new JScrollPane(coverCommentTextArea);
185 builder.add(coverCommentScrollPane,
186 cc.xywh(builder.getColumn(), builder.getRow(), 1, 2));
187 builder.nextLine(2);
188 }
189
190 @Override
191 public boolean apply() {
192 if (!super.apply()) {
193 return false;
194 }
195
196 if (!includeCoverCheckBox.isSelected()) {
197 boolean filenameProvided = false;
198 for (FileChooserPanel documentFileChooserPanel : documentFileChooserPanels) {
199 if (documentFileChooserPanel.getTextField().getText().trim().length() != 0) {
200 filenameProvided = true;
201 if (Settings.CONFIRM_NONPS.getValue()) {
202 if (!checkPostScript(documentFileChooserPanel.getTextField().getText())) {
203 documentFileChooserPanel.getTextField().requestFocus();
204 return false;
205 }
206 }
207 }
208 }
209 if (!filenameProvided) {
210 Dialogs.showError(this, i18n.tr("You must at least send a document or a cover"),
211 i18n.tr("JHylaFAX Error"));
212 documentFileChooserPanels.get(0).getTextField().requestFocus();
213 return false;
214 }
215 }
216
217 Fax fax = createFax();
218 if (fax != null) {
219 if (send(fax)) {
220 if (quitAfterSending) {
221 JHylaFAX.getInstance().exit();
222 }
223 return true;
224 }
225 }
226
227 return false;
228 }
229
230 private boolean checkPostScript(String filename) {
231 try {
232 if (!HylaFAXClientHelper.isPostscript(filename)) {
233 if (Dialogs.showConfirmDialog(this,
234 i18n.tr("Do you really want to send the non PostScript file \"{0}\"?", filename),
235 i18n.tr("JHylaFAX - Send non PostScript file"),
236 JOptionPane.YES_NO_OPTION,
237 Settings.CONFIRM_NONPS) == JOptionPane.NO_OPTION) {
238 return false;
239 }
240 }
241 }
242 catch (IOException e) {
243 logger.debug("Error checking for PostScript", e);
244 ErrorDialog.showError(this, i18n.tr("Could not check for PostScript"),
245 i18n.tr("JHylaFAX Error"),
246 e);
247 return false;
248 }
249 return true;
250 }
251
252 private Fax createFax() {
253 Fax fax = new Fax();
254
255 for (FileChooserPanel documentFileChooserPanel : documentFileChooserPanels) {
256 String filename = documentFileChooserPanel.getTextField().getText();
257 if (filename.trim().length() > 0) {
258 File file = new File(filename);
259 fax.documents.add(file);
260 }
261 }
262
263 if (includeCoverCheckBox.isSelected() && !createFaxCover(fax)) {
264 return null;
265 }
266
267 return fax;
268 }
269
270 private boolean createFaxCover(Fax fax) {
271 if (fax == null) {
272 throw new IllegalArgumentException("value may not be null");
273 }
274
275 String filename;
276 if (Settings.USE_INTERNAL_COVER.getValue()) {
277 filename = "faxcover.ps";
278 fax.coverIn = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
279 } else {
280 filename = Settings.COVER_PATH.getValue();
281 try {
282 fax.coverIn = new FileInputStream(filename);
283 }
284 catch (FileNotFoundException e) {
285 fax.coverIn = null;
286 }
287 }
288 if (fax.coverIn == null) {
289 Dialogs.showError(this, i18n.tr("Could not read cover file: {0}", filename),
290 i18n.tr("JHylaFAX Error"));
291 return false;
292 }
293
294 fax.cover = new FaxCover(Settings.PAPER.getValue());
295 fax.cover.from = coverSenderTextField.getText();
296 fax.cover.to = coverRecepientTextField.getText();
297 fax.cover.regarding = coverSubjectTextField.getText();
298 fax.cover.comments = coverCommentTextArea.getText();
299 fax.cover.todays_date = SimpleDateFormat.getDateTimeInstance().format(new Date());
300 for (Iterator<File> it = fax.documents.iterator(); it.hasNext();) {
301 fax.cover.addDocument(it.next().getAbsolutePath());
302 }
303
304 return true;
305 }
306
307 private boolean send(final Fax fax) {
308 Job<?> ioJob = new Job() {
309 public Object run(ProgressMonitor monitor) throws Exception
310 {
311 monitor.setTotalSteps(13 + fax.documents.size() * 10);
312
313 HylaFAXClient client = JHylaFAX.getInstance().getConnection(monitor);
314 monitor.work(1);
315
316 client.mode(HylaFAXClient.MODE_STREAM);
317 client.type(HylaFAXClient.TYPE_IMAGE);
318
319 String serverCoverFilename = null;
320 if (fax.cover != null && fax.coverIn != null) {
321 monitor.setText(i18n.tr("Generating cover"));
322 SubTaskProgressMonitor coverMonitor = new SubTaskProgressMonitor(monitor, 5, 0);
323 StringBuffer data = fax.cover.generate(fax.coverIn, coverMonitor);
324 coverMonitor.done();
325
326
327 byte[] buffer = data.toString().getBytes(FaxCover.CHARSET);
328 TransferMonitor transferMonitor = new TransferMonitor(monitor, 5, buffer.length);
329 client.addTransferListener(transferMonitor);
330 InputStream in = new ByteArrayInputStream(buffer);
331 try {
332 serverCoverFilename = client.putTemporary(in);
333 }
334 finally {
335 transferMonitor.transferCompleted();
336 client.removeTransferListener(transferMonitor);
337 in.close();
338 }
339
340 monitor.work(0);
341 }
342 else {
343 monitor.work(10);
344 }
345
346 monitor.setText(i18n.tr("Uploading documents"));
347 List<String> serverFilenames = new ArrayList<String>();
348 for (File file : fax.documents) {
349 TransferMonitor transferMonitor = new TransferMonitor(monitor, 10, file.length());
350 client.addTransferListener(transferMonitor);
351 InputStream in = new BufferedInputStream(new FileInputStream(file));
352 try {
353 serverFilenames.add(client.putTemporary(in));
354 }
355 finally {
356 transferMonitor.transferCompleted();
357 client.removeTransferListener(transferMonitor);
358 in.close();
359 }
360
361 monitor.work(0);
362 }
363
364 gnu.hylafax.Job sendJob = client.createJob();
365 HylaFAXClientHelper.applyParameter(sendJob, getJob());
366 if (serverCoverFilename != null) {
367 if (Settings.SEND_COVER_AS_DOCUMENT.getValue()) {
368 sendJob.addDocument(serverCoverFilename);
369 }
370 else {
371 sendJob.setProperty("COVER ", serverCoverFilename);
372 }
373 }
374 for (String filename : serverFilenames) {
375 sendJob.addDocument(filename);
376 }
377 monitor.work(1);
378
379 client.submit(sendJob);
380 monitor.work(1);
381
382 return null;
383 }
384 };
385
386 try {
387 JHylaFAX.getInstance().runJob(SendDialog.this, ioJob);
388 JHylaFAX.getInstance().updateTables();
389 }
390 catch (UserAbortException e) {
391 return false;
392 }
393 catch (Exception e) {
394 logger.debug("Error sending fax", e);
395 ErrorDialog.showError(this, i18n.tr("Could not send fax"),
396 i18n.tr("JHylaFAX Error"),
397 e);
398 return false;
399 }
400 return true;
401 }
402
403 private File saveCover(final Fax fax) {
404 if (fax.cover == null || fax.coverIn == null) {
405 throw new IllegalArgumentException("fax.cover and fax.coverIn must not be null");
406 }
407
408 Job<File> ioJob = new Job<File>() {
409 public File run(ProgressMonitor monitor) throws Exception
410 {
411 monitor.setTotalSteps(10);
412
413 monitor.setText(i18n.tr("Generating cover"));
414 SubTaskProgressMonitor coverMonitor = new SubTaskProgressMonitor(monitor, 5, 0);
415 StringBuffer data = fax.cover.generate(fax.coverIn, coverMonitor);
416 coverMonitor.done();
417
418 File outputFile = File.createTempFile("jhylafax", ".ps");
419 outputFile.deleteOnExit();
420 OutputStream out = new FileOutputStream(outputFile);
421 monitor.setText(i18n.tr("Saving cover"));
422 try {
423 out.write(data.toString().getBytes(FaxCover.CHARSET));
424 }
425 finally {
426 out.close();
427 }
428 monitor.work(5);
429
430 return outputFile;
431 }
432 };
433
434 try {
435 return JHylaFAX.getInstance().runJob(SendDialog.this, ioJob);
436 }
437 catch (UserAbortException e) {
438 return null;
439 }
440 catch (Exception e) {
441 logger.debug("Error previewing cover", e);
442 ErrorDialog.showError(this, i18n.tr("Could not preview cover"),
443 i18n.tr("JHylaFAX Error"), e);
444 return null;
445 }
446 }
447
448 public void updateLabels() {
449 super.updateLabels();
450
451 setTitle(i18n.tr("Send Fax"));
452 documentLabel.setText(i18n.tr("Document"));
453 includeCoverLabel.setText(i18n.tr("Include Cover"));
454 coverSenderLabel.setText(i18n.tr("Sender"));
455 coverRecepientLabel.setText(i18n.tr("Recepient"));
456 coverSubjectLabel.setText(i18n.tr("Subject"));
457 coverCommentLabel.setText(i18n.tr("Comment"));
458
459 previewCoverAction.updateLabels();
460 moreDocumentsAction.updateLabels();
461 }
462
463 public void setDocument(String document) {
464 documentFileChooserPanels.get(0).getTextField().setText(document);
465 }
466
467
468
469
470 private class Fax {
471 FaxCover cover;
472 InputStream coverIn;
473 List<File> documents = new ArrayList<File>();
474 }
475
476 private class PreviewCoverAction extends AbstractXNapAction implements LocaleChangeListener{
477
478 public PreviewCoverAction() {
479
480 }
481
482 public void actionPerformed(ActionEvent event) {
483 if (!includeCoverCheckBox.isSelected()) {
484 throw new IllegalStateException("Cover page is not enabled");
485 }
486
487 String viewerPath = JHylaFAXHelper.getViewerPath("docq");
488 if (viewerPath == null) {
489 return;
490 }
491
492 Fax fax = createFax();
493 if (fax == null) {
494 return;
495 }
496
497 File tempFile = saveCover(fax);
498 if (tempFile != null) {
499 JHylaFAXHelper.view(viewerPath, new File[] { tempFile });
500 }
501 }
502
503 public void updateLabels() {
504 putValue(Action.NAME, i18n.tr("Preview Cover"));
505 putValue(Action.SHORT_DESCRIPTION, i18n.tr("Opens an external programm to preview the cover page"));
506 }
507
508 }
509
510 private class MoreDocumentsAction extends AbstractXNapAction implements LocaleChangeListener{
511
512 public MoreDocumentsAction() {
513 }
514
515 public void actionPerformed(ActionEvent event) {
516 FileChooserPanel documentFileChooserPanel = addDocumentFileChooser();
517 documentFileChooserPanel.getTextField().requestFocus();
518 }
519
520 public void updateLabels() {
521 putValue(Action.NAME, i18n.tr("More"));
522 putValue(Action.SHORT_DESCRIPTION, i18n.tr("Displays an additional field to enter a document filename"));
523 }
524
525 }
526
527 private class MyFileChooserPanel extends FileChooserPanel {
528
529 public MyFileChooserPanel(int columns)
530 {
531 super(columns);
532 }
533
534 @Override
535 protected void fileSelected(File file)
536 {
537 File[] files = getFileChooser().getSelectedFiles();
538 if (files != null && files.length > 1) {
539
540 for (int i = 1; i < files.length; i++) {
541
542 FileChooserPanel chooser = addDocumentFileChooser();
543 chooser.setFile(files[i]);
544 }
545 }
546
547 getFileChooser().setSelectedFiles(null);
548 }
549
550 }
551
552 protected FileChooserPanel addDocumentFileChooser()
553 {
554 FileChooserPanel documentFileChooserPanel = new MyFileChooserPanel(DEFAULT_COLUMNS);
555 documentFileChooserPanel.setFileChooser(documentFileChooserPanels.get(0).getFileChooser());
556 documentFileChooserPanels.add(documentFileChooserPanel);
557 documentPanelBuilder.append("", documentFileChooserPanel);
558 documentPanelBuilder.nextLine();
559 pack();
560 return documentFileChooserPanel;
561 }
562
563 public void addDocument(String filename)
564 {
565 FileChooserPanel panel = addDocumentFileChooser();
566 panel.getTextField().setText(filename);
567 }
568
569 public void setQuitAfterSending(boolean quitAfterSending)
570 {
571 this.quitAfterSending = quitAfterSending;
572 }
573
574 }