OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 180 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
 * 
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each file.
 */
 
 package org.openconcerto.erp.core.edm;

import org.openconcerto.erp.core.common.ui.ScrollablePanel;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.FileUtils;

import java.awt.Color;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

public class AttachmentPanel extends JPanel {

    private final SQLRowAccessor rowSource;
    private final Collection<SQLRowAccessor> rowSecondaires;
    private List<ListDataListener> listeners = new ArrayList<>();

    private int idParent = 1;
    private List<Integer> parents = new ArrayList<>();
    private List<String> parentsNames = new ArrayList<>();
    private Set<Attachment> selectedAttachments = new HashSet<>();
    private List<FilePanel> filePanels = new ArrayList<>();

    public AttachmentPanel(SQLRowAccessor rowSource) {
        this(rowSource, Collections.emptyList());
    }

    public AttachmentPanel(SQLRowAccessor rowSource, Collection<SQLRowAccessor> rowSecondaires) {
        super();
        this.rowSource = rowSource;
        this.rowSecondaires = rowSecondaires;

        this.setLayout(new GridBagLayout());
        this.parents.add(1);
        this.parentsNames.add("Racine");
        initUI();
        setFocusable(true);
    }

    public void addListener(ListDataListener l) {
        this.listeners.add(l);
    }

    public void removeListener(ListDataListener l) {
        this.listeners.remove(l);
    }

    public void fireDataChanged() {
        for (ListDataListener listDataListener : this.listeners) {
            listDataListener.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, 0));
        }
    }

    public int getAttachementsSize() {
        return this.filePanels.size();
    }

    public void initUI() {
        this.filePanels.clear();
        this.invalidate();
        this.removeAll();
        GridBagConstraints c = new DefaultGridBagConstraints();

        // Recupération de la liste des fichiers

        // TODO requete dans un SwingWorker
        final SQLTable tableAttachment = this.rowSource.getTable().getTable("ATTACHMENT");
        SQLRowValues rowVals = new SQLRowValues(tableAttachment);
        rowVals.putNulls(tableAttachment.getFieldsName());

        SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(rowVals);
        Where where = new Where(tableAttachment.getField("SOURCE_TABLE"), "=", this.rowSource.getTable().getName());
        where = where.and(new Where(tableAttachment.getField("SOURCE_ID"), "=", this.rowSource.getID()));

        where = where.and(new Where(tableAttachment.getField("ID_PARENT"), "=", this.idParent));
        for (SQLRowAccessor rowSecondaire : this.rowSecondaires) {

            Where whereSec = new Where(tableAttachment.getField("SOURCE_TABLE"), "=", rowSecondaire.getTable().getName());
            whereSec = whereSec.and(new Where(tableAttachment.getField("SOURCE_ID"), "=", rowSecondaire.getID()));

            where = where.or(whereSec);
        }
        final List<SQLRowValues> rAttachments = fetcher.fetch(where);
        c.fill = GridBagConstraints.BOTH;
        c.anchor = GridBagConstraints.WEST;
        c.gridx = 0;
        c.gridy = 0;
        // Folder paths
        if (this.parents.size() > 1) {
            JPanel navPanel = new JPanel();
            navPanel.setBackground(Color.WHITE);
            navPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
            navPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 8, 2));

            for (int i = 0; i < this.parents.size(); i++) {
                JLabel b = new JLabel(" " + this.parentsNames.get(i) + " ");
                b.setOpaque(true);
                b.setBackground(new Color(230, 240, 255));
                navPanel.add(b);
                final int id = this.parents.get(i);
                final int index = i;
                if (i < this.parents.size() - 1) {
                    b.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mousePressed(MouseEvent e) {
                            AttachmentPanel.this.idParent = id;
                            int nb = AttachmentPanel.this.parents.size() - index - 1;
                            for (int n = 0; n < nb; n++) {
                                final int pos = AttachmentPanel.this.parents.size() - 1;
                                AttachmentPanel.this.parents.remove(pos);
                                AttachmentPanel.this.parentsNames.remove(pos);
                            }
                            clearSelection();
                            initUI();
                        }
                    });
                }
                if (i < this.parents.size() - 1) {
                    b.setDropTarget(new DropTarget() {

                        @Override
                        public synchronized void drop(DropTargetDropEvent dtde) {
                            dtde.acceptDrop(DnDConstants.ACTION_MOVE);
                            Transferable t = dtde.getTransferable();
                            try {
                                for (int i = 0; i < t.getTransferDataFlavors().length; i++) {
                                    final DataFlavor dataFlavor = t.getTransferDataFlavors()[i];
                                    if (dataFlavor.isMimeTypeEqual(DataFlavor.javaSerializedObjectMimeType)) {
                                        @SuppressWarnings("unchecked")
                                        List<Attachment> attachments = (List<Attachment>) t.getTransferData(dataFlavor);
                                        AttachmentUtils utils = new AttachmentUtils();
                                        for (Attachment a : attachments) {
                                            if (a.getParentId() != id) {
                                                utils.move(a, id);
                                            }
                                        }
                                        initUI();
                                        break;
                                    }
                                }

                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }

            }
            this.add(navPanel, c);
            c.gridy++;
        }

        // Tools
        final JPanel toolbar = new JPanel();
        toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
        final JButton addFolderButton = new JButton("Nouveau dossier");
        toolbar.add(addFolderButton);
        final JButton addFileButton = new JButton("Ajouter un fichier");
        toolbar.add(addFileButton);
        final JButton addURLButton = new JButton("Ajouter une URL");
        toolbar.add(addURLButton);

        final JProgressBar progressBar = new JProgressBar(0, 100);
        progressBar.setValue(100);
        progressBar.setStringPainted(true);
        progressBar.setVisible(false);
        toolbar.add(progressBar);

        this.add(toolbar, c);

        c.gridy++;

        addFolderButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                AttachmentUtils utils = new AttachmentUtils();
                try {
                    utils.createFolder("Nouveau dossier", AttachmentPanel.this.rowSource, AttachmentPanel.this.idParent);
                } catch (SQLException e1) {
                    JOptionPane.showMessageDialog(null, "Impossible de créer le dossier.", "Erreur", JOptionPane.ERROR_MESSAGE);
                }
                initUI();

            }
        });

        addFileButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                final Frame frame = SwingThreadUtils.getAncestorOrSelf(Frame.class, (Component) e.getSource());
                final FileDialog fd = new FileDialog(frame, "Ajouter un fichier", FileDialog.LOAD);
                fd.setVisible(true);
                final String fileName = fd.getFile();
                if (fileName != null) {
                    try {
                        File inFile = new File(fd.getDirectory(), fileName);
                        AttachmentUtils utils = new AttachmentUtils();
                        utils.uploadFile(inFile, AttachmentPanel.this.rowSource, AttachmentPanel.this.idParent);
                        initUI();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                        JOptionPane.showMessageDialog(AttachmentPanel.this, "Erreur lors de l'ajout du fichier " + fileName + "(" + ex.getMessage() + ")");
                    }
                }
            }
        });

        addURLButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    final Frame frame = SwingThreadUtils.getAncestorOrSelf(Frame.class, (Component) e.getSource());
                    final String fileName = JOptionPane.showInputDialog(frame, "Veuillez entrer votre URL");
        
                    if (fileName != null) {
                        AttachmentUtils utils = new AttachmentUtils();
                        try {
                            utils.createURL(fileName, rowSource, idParent);
                        } catch (SQLException e1) {
                            JOptionPane.showMessageDialog(null, "Impossible de créer l'URL.", "Erreur", JOptionPane.ERROR_MESSAGE);
                        }
                        initUI();
                    }
                }
            });

        ScrollablePanel files = new ScrollablePanel() {
            @Override
            public Dimension getPreferredSize() {
                int w = getSize().width;
                int nbPerRow = (w - 5) / (FilePanel.PREFERRED_WIDTH + 5);
                if (nbPerRow < 1) {
                    nbPerRow = 1;
                }
                int nbRow = 1 + (getComponentCount() / nbPerRow);
                if (nbRow < 1) {
                    nbRow = 1;
                }
                return new Dimension(w, 5 + nbRow * (FilePanel.PREFERRED_HEIGHT + 5));
            }

        };
        files.setOpaque(true);
        files.setBackground(Color.WHITE);
        files.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.FIT);
        files.setScrollableHeight(ScrollablePanel.ScrollableSizeHint.NONE);
        files.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
        final List<Attachment> attachments = new ArrayList<>(rAttachments.size());
        for (final SQLRowValues sqlRowValues : rAttachments) {
            final Attachment a = new Attachment(sqlRowValues);
            attachments.add(a);
        }
        Collections.sort(attachments, new Comparator<Attachment>() {

            @Override
            public int compare(Attachment o1, Attachment o2) {
                if (o1.isFolder() && !o2.isFolder()) {
                    return -1;
                }
                if (!o1.isFolder() && o2.isFolder()) {
                    return 1;
                }
                return o1.getName().compareTo(o2.getName());
            }
        });

        // Liste des fichiers
        for (final Attachment a : attachments) {
            final FilePanel filePanel = new FilePanel(a, this);
            this.filePanels.add(filePanel);
            filePanel.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        if (a.isFolder()) {
                            openFolder(a);
                        } else if( a.getMimeType().equals(Attachment.MIMETYPE_URL) ) {
                            try {
                                Desktop.getDesktop().browse(new URI(a.getFileName()));
                            } catch (IOException | URISyntaxException e1) {
                                ExceptionHandler.handle("Malformation URL", e1);
                            }
                        } else {
                            final Thread t = new Thread() {
                                @Override
                                public void run() {
                                    AttachmentUtils utils = new AttachmentUtils();
                                    File f = utils.getFile(a);
                                    if (f == null) {
                                        SwingUtilities.invokeLater(new Runnable() {
                                            public void run() {
                                                JOptionPane.showMessageDialog(null, "Impossible de récupérer le fichier.", "Erreur", JOptionPane.ERROR_MESSAGE);
                                            }
                                        });
                                    } else {
                                        try {
                                            FileUtils.openFile(f);
                                        } catch (IOException e1) {
                                            ExceptionHandler.handle("Erreur lors de l'ouverture du fichier.", e1);
                                        }

                                    }
                                }
                            };
                            t.start();
                        }
                    }
                }

            });
            files.add(filePanel);

        }

        c.gridx = 0;
        c.gridy++;
        c.weightx = 1;
        c.weighty = 1;

        final JScrollPane scroll = new JScrollPane(files);
        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scroll.setMinimumSize(new Dimension((int) (400 * 1.618), 400));
        scroll.setPreferredSize(new Dimension((int) (400 * 1.618), 400));
        scroll.setBackground(Color.WHITE);
        scroll.getViewport().setBackground(Color.WHITE);
        this.add(scroll, c);
        scroll.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                clearSelection();
                updatePanels();
            }
        });

        this.validate();
        this.repaint();

        DropTarget dt = new DropTarget() {

            @Override
            public synchronized void drop(DropTargetDropEvent dtde) {
                dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                Transferable t = dtde.getTransferable();
                try {
                    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                        @SuppressWarnings("unchecked")
                        List<File> fileList = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
                        // TODO faire en arriere plan, mettre une jauge à droite du bouton ajouter
                        // et mettre un bouton d'annulation
                        AttachmentUtils utils = new AttachmentUtils();
                        boolean cancelledByUser = false;
                        for (File f : fileList) {
                            if (cancelledByUser) {
                                break;
                            }
                            try {
                                if (!f.isDirectory()) {
                                    utils.uploadFile(f, AttachmentPanel.this.rowSource, AttachmentPanel.this.idParent);
                                }
                            } catch (Exception ex) {
                                ex.printStackTrace();
                                JOptionPane.showMessageDialog(AttachmentPanel.this, "Erreur lors de l'ajout du fichier " + f.getAbsolutePath() + "(" + ex.getMessage() + ")");
                            }
                        }
                        initUI();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        files.setDropTarget(dt);
        scroll.getViewport().setDropTarget(dt);
        fireDataChanged();
    }

    public Set<Attachment> getSelectedAttachments() {
        return this.selectedAttachments;
    }

    public void select(Attachment a) {
        this.selectedAttachments.add(a);
    }

    public void deselect(Attachment a) {
        this.selectedAttachments.remove(a);
    }

    public boolean isSelected(Attachment a) {
        return this.selectedAttachments.contains(a);
    }

    public void clearSelection() {
        this.selectedAttachments.clear();
    }

    public void updatePanels() {
        for (FilePanel p : this.filePanels) {
            p.updateBackgroundFromState();
        }
    }

    public void openFolder(final Attachment a) {
        if (!a.isFolder()) {
            throw new IllegalStateException(a.getName() + " is not a folder");
        }
        clearSelection();
        this.idParent = a.getId();
        this.parents.add(a.getId());
        this.parentsNames.add(a.getName());
        initUI();
    }
}