OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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