OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 61 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.openoffice.generation.view;
15
 
16
import org.openconcerto.openoffice.Log;
17
import org.openconcerto.openoffice.ODSingleXMLDocument;
18
import org.openconcerto.openoffice.OOUtils;
19
import org.openconcerto.openoffice.generation.GenerationTask;
20
import org.openconcerto.openoffice.generation.ReportGeneration;
21
import org.openconcerto.openoffice.generation.TaskStatus;
22
import org.openconcerto.openoffice.generation.desc.ReportType;
23
import org.openconcerto.openoffice.generation.desc.ReportTypes;
24
import org.jopendocument.link.Component;
25
import org.jopendocument.link.OOConnexion;
26
import org.openconcerto.utils.EmailClient;
27
import org.openconcerto.utils.ExceptionHandler;
28
import org.openconcerto.utils.FileUtils;
29
import org.openconcerto.utils.model.ListComboBoxModel;
30
 
31
import java.awt.Desktop;
32
import java.awt.Dimension;
33
import java.awt.GridBagConstraints;
34
import java.awt.GridBagLayout;
35
import java.awt.Insets;
36
import java.awt.event.ActionEvent;
37
import java.awt.event.ActionListener;
38
import java.beans.PropertyChangeEvent;
39
import java.beans.PropertyChangeListener;
40
import java.io.File;
41
import java.io.FileNotFoundException;
42
import java.io.IOException;
43
import java.util.ArrayList;
44
import java.util.LinkedHashMap;
45
import java.util.List;
46
import java.util.Map;
47
import java.util.Map.Entry;
48
import java.util.concurrent.Future;
49
 
50
import javax.swing.AbstractAction;
51
import javax.swing.AbstractListModel;
52
import javax.swing.JButton;
53
import javax.swing.JComboBox;
54
import javax.swing.JComponent;
55
import javax.swing.JLabel;
56
import javax.swing.JList;
57
import javax.swing.JOptionPane;
58
import javax.swing.JPanel;
59
import javax.swing.JScrollPane;
60
import javax.swing.SwingUtilities;
61
 
62
import org.jdom.JDOMException;
63
 
64
/**
65
 * A panel to choose a ReportType, see the tasks of the generation, and optionnaly open the
66
 * document. NOTE: you have to call {@link #enableGeneration(boolean)} before being able to
67
 * generate, because it's set to false in the constructor.
68
 *
69
 * @author ILM Informatique 27 déc. 2003
70
 * @param <R> type of generation
71
 */
72
public abstract class BaseGenerationRapport<R extends ReportGeneration<?>> extends JPanel {
73
 
74
    static public enum FileAction {
75
        DO_NOTHING("ne rien faire"), OPEN("ouvrir le fichier"), MAIL("envoyer par courriel");
76
 
77
        private final String label;
78
 
79
        private FileAction(String label) {
80
            this.label = label;
81
        }
82
 
83
        @Override
84
        public String toString() {
85
            return this.label;
86
        }
87
    }
88
 
89
    private JComboBox typeRapportComboSelection;
90
 
91
    private JButton genererButton;
92
    private JComboBox fileActionCombo;
93
 
94
    private JList tasksView;
95
    private JLabel status;
96
 
97
    // le groupe dans lequel doivent être toutes les thread de la génération
98
    private final ThreadGroup thg;
99
 
100
    public BaseGenerationRapport() throws JDOMException, IOException {
101
        this.thg = new ThreadGroup(this + " thread group");
102
        this.uiInit();
103
        this.setStatus("Inactif");
104
    }
105
 
106
    protected Map<String, JComponent> getEntries() {
107
        return new LinkedHashMap<String, JComponent>();
108
    }
109
 
110
    protected File getReportDir() {
111
        return null;
112
    }
113
 
114
    private void uiInit() throws JDOMException, IOException {
115
        setLayout(new GridBagLayout());
116
        GridBagConstraints c = new GridBagConstraints();
117
        c.ipadx = 40;
118
        c.insets = new Insets(2, 5, 0, 0);
119
        c.gridx = 0;
120
        c.gridy = 0;
121
        c.gridheight = 1;
122
        c.gridwidth = 1;
123
        c.fill = GridBagConstraints.HORIZONTAL;
124
 
125
        final Map<String, JComponent> allEntries = new LinkedHashMap<String, JComponent>();
126
        this.typeRapportComboSelection = new JComboBox(new ListComboBoxModel(this.getTypes().getTypes()));
127
        allEntries.put("Type de rapport", this.typeRapportComboSelection);
128
        allEntries.putAll(this.getEntries());
129
 
130
        for (final Map.Entry<String, JComponent> e : allEntries.entrySet()) {
131
            c.gridx = 0;
132
            c.gridy++;
133
            this.add(new JLabel(e.getKey()), c);
134
            c.gridx++;
135
            c.weightx = 1;
136
            this.add(e.getValue(), c);
137
            c.weightx = 0;
138
        }
139
        final File reportDir = getReportDir();
140
        if (reportDir != null) {
141
            c.gridx = 1;
142
            c.gridy++;
143
            c.weightx = 1;
144
            this.add(new JButton(new AbstractAction("Ouvrir le dossier des rapports") {
145
                @Override
146
                public void actionPerformed(ActionEvent e) {
147
                    try {
148
                        Desktop.getDesktop().browse(reportDir.toURI());
149
                    } catch (Exception e1) {
150
                        JOptionPane.showMessageDialog(BaseGenerationRapport.this, "Impossible d'ouvrir le dossier", "Erreur", JOptionPane.ERROR_MESSAGE);
151
                    }
152
                }
153
            }), c);
154
            c.weightx = 0;
155
        }
156
 
157
        c.gridx = 0;
158
        c.gridy++;
159
        this.genererButton = new JButton("Générer le rapport et");
160
        this.add(this.genererButton, c);
161
        this.genererButton.setEnabled(false);
162
        this.genererButton.addActionListener(new GenerateAction());
163
 
164
        c.gridx++;
165
        this.fileActionCombo = new JComboBox(getAllowedActions());
166
        this.fileActionCombo.setSelectedItem(FileAction.OPEN);
167
        this.add(this.fileActionCombo, c);
168
        this.fileActionCombo.setEnabled(false);
169
 
170
        c.gridx = 0;
171
        c.gridy++;
172
        c.gridwidth = GridBagConstraints.REMAINDER;
173
        this.status = new JLabel();
174
        this.add(this.status, c);
175
 
176
        c.gridy++;
177
        this.tasksView = new JList(new TasksModel());
178
        this.tasksView.setCellRenderer(new GenerationTaskView());
179
        c.fill = GridBagConstraints.BOTH;
180
        c.weighty = 1;
181
        JScrollPane scroll = new JScrollPane(this.tasksView);
182
        scroll.setPreferredSize(new Dimension(200, 400));
183
        this.add(scroll, c);
184
    }
185
 
186
    /**
187
     * Permet de modifier la liste des tâches.
188
     *
189
     * @author Sylvain CUAZ
190
     */
191
    private static final class TasksModel extends AbstractListModel implements PropertyChangeListener {
192
        private List<GenerationTask> tasks;
193
 
194
        {
195
            this.tasks = new ArrayList<GenerationTask>(15);
196
        }
197
 
198
        public int getSize() {
199
            return this.tasks.size();
200
        }
201
 
202
        public Object getElementAt(int index) {
203
            return this.tasks.get(index);
204
        }
205
 
206
        void add(GenerationTask task) {
207
            this.tasks.add(task);
208
            task.addPropertyChangeListener(this);
209
            this.fireIntervalAdded(this, this.tasks.size(), this.tasks.size());
210
        }
211
 
212
        void clear() {
213
            for (final GenerationTask t : this.tasks) {
214
                t.removePropertyChangeListener(this);
215
            }
216
            this.fireIntervalRemoved(this, 0, this.tasks.size());
217
            this.tasks.clear();
218
        }
219
 
220
        /*
221
         * Une tache a changé.
222
         */
223
        public void propertyChange(PropertyChangeEvent evt) {
224
            int index = this.tasks.indexOf(evt.getSource());
225
            this.fireContentsChanged(this, index, index);
226
        }
227
    }
228
 
229
    /**
230
     * Interrompt la génération.
231
     */
232
    public final void interrupt() {
233
        // pas de threads active, quand pas génération
234
        this.thg.interrupt();
235
    }
236
 
237
    class GenerateAction implements ActionListener {
238
        public GenerateAction() {
239
        }
240
 
241
        public void actionPerformed(ActionEvent e) {
242
            enableGeneration(false);
243
            final FileAction sel = (FileAction) BaseGenerationRapport.this.fileActionCombo.getSelectedItem();
244
            // "génération..."
245
            new Thread(BaseGenerationRapport.this.thg, new Runnable() {
246
                @Override
247
                public void run() {
248
                    generate(sel);
249
                    // toujours le faire, même si interrompu
250
                    SwingUtilities.invokeLater(new Runnable() {
251
                        public void run() {
252
                            enableGeneration(true);
253
                        }
254
                    });
255
                }
256
            }).start();
257
        }
258
    }
259
 
260
    protected final void enableGeneration(boolean b) {
261
        this.fileActionCombo.setEnabled(b);
262
        this.genererButton.setEnabled(b);
263
    }
264
 
265
    // doit s'exécuter dans this.thg
266
    protected final void generate(final FileAction sel) {
267
        final ReportType type = (ReportType) this.typeRapportComboSelection.getSelectedItem();
268
        final R rg = this.createGeneration(type);
269
        rg.addTaskListener(new PropertyChangeListener() {
270
            public void propertyChange(PropertyChangeEvent evt) {
271
                final TaskStatus st = (TaskStatus) evt.getOldValue();
272
                if (st.getState().equals(TaskStatus.State.NOT_STARTED))
273
                    addTask((GenerationTask) evt.getSource());
274
            }
275
 
276
        });
277
 
278
        if (Thread.currentThread().isInterrupted())
279
            return;
280
 
281
        Map<String, ODSingleXMLDocument> report = null;
282
        try {
283
            report = this.generate(rg);
284
            if (report != null) {
285
                for (Entry<String, ODSingleXMLDocument> e : report.entrySet()) {
286
                    try {
287
                        final File reportFile = e.getValue().saveAs(this.getFile(rg, e.getKey()));
288
                        if (sel == FileAction.OPEN)
289
                            OOUtils.open(reportFile);
290
                        else if (sel == FileAction.MAIL) {
291
                            final File fileOutPDF = FileUtils.addSuffix(reportFile, ".pdf");
292
                            try {
293
                                final OOConnexion conn = OOConnexion.create();
294
                                if (conn == null)
295
                                    throw new IllegalStateException("OpenOffice n'a pu être trouvé");
296
                                final Component doc = conn.loadDocument(reportFile, true);
297
                                final Future<File> pdf = doc.saveToPDF(fileOutPDF, "writer_pdf_Export");
298
                                doc.close();
299
                                conn.closeConnexion();
300
                                // can wait for the pdf since we're not in the EDT
301
                                EmailClient.getPreferred().compose(getEmailRecipient(rg), "Rapport", null, pdf.get());
302
                            } catch (Exception exn) {
303
                                exn.printStackTrace();
304
                                ExceptionHandler.handle("Impossible de charger le document OpenOffice dans le logiciel de courriel", exn);
305
                            }
306
                        }
307
                    } catch (FileNotFoundException exn) {
308
                        // TODO tester pb de droits
309
                        ExceptionHandler.handle(BaseGenerationRapport.this, "Le fichier est déjà ouvert, veuillez le refermer avant de générer.", exn);
310
                    } catch (IOException exn) {
311
                        ExceptionHandler.handle(BaseGenerationRapport.this, "Impossible de sauver le rapport", exn);
312
                    }
313
                }
314
            }
315
        } catch (Throwable e) {
316
            ExceptionHandler.handle(BaseGenerationRapport.this, "Impossible de générer le rapport", e);
317
        }
318
    }
319
 
320
    private Map<String, ODSingleXMLDocument> generate(org.openconcerto.openoffice.generation.ReportGeneration<?> rg) throws Throwable {
321
        clearTasks();
322
        setStatus("Génération en cours...");
323
 
324
        if (Thread.currentThread().isInterrupted())
325
            return null;
326
 
327
        final long start = System.currentTimeMillis();
328
        Map<String, ODSingleXMLDocument> report = null;
329
        String s;
330
        Throwable t = null;
331
        try {
332
            report = rg.generateMulti();
333
            if (report == null) {
334
                s = "Génération interrompue.";
335
            } else {
336
                s = "Rapport généré en " + (System.currentTimeMillis() - start) / 1000 + " secondes.";
337
            }
338
        } catch (Throwable e) {
339
            s = "Erreur de génération.";
340
            t = e;
341
        }
342
 
343
        setStatus(s);
344
        if (t == null)
345
            return report;
346
        else
347
            throw t;
348
    }
349
 
350
    private final void addTask(final GenerationTask task) {
351
        SwingUtilities.invokeLater(new Runnable() {
352
            public void run() {
353
                ((TasksModel) BaseGenerationRapport.this.tasksView.getModel()).add(task);
354
            }
355
        });
356
 
357
    }
358
 
359
    private final void clearTasks() {
360
        SwingUtilities.invokeLater(new Runnable() {
361
            public void run() {
362
                ((TasksModel) BaseGenerationRapport.this.tasksView.getModel()).clear();
363
            }
364
        });
365
    }
366
 
367
    private final void setStatus(final String status) {
368
        Log.get().info(this + " status: " + status);
369
        SwingUtilities.invokeLater(new Runnable() {
370
            public void run() {
371
                BaseGenerationRapport.this.status.setText(status);
372
            }
373
        });
374
    }
375
 
376
    public String toString() {
377
        return "Generation panel";
378
    }
379
 
380
    abstract protected ReportTypes getTypes() throws JDOMException, IOException;
381
 
382
    abstract protected R createGeneration(final ReportType type);
383
 
384
    abstract protected File getFile(final R rg, String docID);
385
 
386
    protected String getEmailRecipient(final R rg) {
387
        return null;
388
    }
389
 
390
    protected FileAction[] getAllowedActions() {
391
        return FileAction.values();
392
    }
393
}