OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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