net.leboxondelex.daplomb.ui.facets.CollageFacet.java Source code

Java tutorial

Introduction

Here is the source code for net.leboxondelex.daplomb.ui.facets.CollageFacet.java

Source

/*************************************************************************************************
 * Copyright (c) 2013, Lex @ le boxon de Lex: http://le-boxon-de-lex.fr
 *
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 *
 * Additional permission under GNU GPL version 3 section 7
 *
 * If you modify this Program, or any covered work, by linking or combining it with Eclipse (or
 * a modified version of that library), containing parts covered by the terms of Eclipse Public
 * License (EPL), the licensors of this Program grant you additional permission to convey the
 * resulting work. Corresponding Source for a non-source form of such a combination shall include
 * the source code for the parts of D'Aplomb used as well as that of the covered work.
 ***************************************************************************************************/

package net.leboxondelex.daplomb.ui.facets;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.util.List;

import net.leboxondelex.daplomb.collages.Collage;
import net.leboxondelex.daplomb.collages.CollageBuilder;
import net.leboxondelex.daplomb.collages.CollageIO;
import net.leboxondelex.daplomb.collages.instructions.AbstractInstruction;
import net.leboxondelex.daplomb.collages.instructions.AddImageInstruction;
import net.leboxondelex.daplomb.collages.instructions.BackgroundInstruction;
import net.leboxondelex.daplomb.collages.instructions.BordersInstruction;
import net.leboxondelex.daplomb.collages.instructions.BreakLineInstruction;
import net.leboxondelex.daplomb.collages.instructions.ShiftInstruction;
import net.leboxondelex.daplomb.images.StaticImageViewer;
import net.leboxondelex.daplomb.managers.PreferencesManager;
import net.leboxondelex.daplomb.managers.ResourceRegistry;
import net.leboxondelex.daplomb.model.AssemblyImage;
import net.leboxondelex.daplomb.ui.dialogs.CropImageDialog;
import net.leboxondelex.daplomb.ui.swt.ImageCanvas;
import net.leboxondelex.daplomb.utils.ImageUtils;
import net.leboxondelex.daplomb.utils.LogUtils;
import net.leboxondelex.daplomb.utils.StringUtils;
import net.leboxondelex.daplomb.utils.Utils;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

/**
 * @author Lex
 */
public class CollageFacet extends ApplicationFacet {

    private static final String COLLAGES_DIR = "collages";
    private static final String GHOST_BUTTON_E = "Masquer";
    private static final String GHOST_BUTTON_D = "Dmasquer";
    private static final String DIM = "Dimensions du Collage :";
    private static final int COL_WIDTH = 25;

    private final File backupFile = new File(System.getProperty("java.io.tmpdir"), "daplomb_collage.backup");
    private Collage collage;
    private CollageBuilder collageBuilder;

    private AssemblyImage previewImg;
    private final TableViewer instructionsViewer;
    private final ImageCanvas previewCanvas;
    private final Label dimensionsLabel;
    private Font appFont;

    /**
     * Constructor.
     * @param parent
     * @param appFont
     */
    public CollageFacet(Composite parent, Font appFont) {
        super(parent);
        this.appFont = appFont;

        if (this.backupFile.exists()) {
            try {
                this.collage = CollageIO.readCollage(this.backupFile);

            } catch (IOException e) {
                LogUtils.log(e);
            }
        }

        if (this.collage == null)
            this.collage = new Collage();

        this.collageBuilder = new CollageBuilder(this.collage);
        GridLayoutFactory.swtDefaults().numColumns(3).equalWidth(true).margins(10, 10).spacing(20, 0).applyTo(this);
        setLayoutData(new GridData(GridData.FILL_BOTH));

        // The left part
        Composite leftPart = new Composite(this, SWT.NONE);
        GridLayoutFactory.swtDefaults().margins(0, 0).spacing(0, 5).applyTo(leftPart);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(leftPart);

        Label l = new Label(leftPart, SWT.NONE);
        l.setText("Votre collage se construit en composant des instructions.");
        l.setFont(appFont);

        Composite allButtonsComposite = new Composite(leftPart, SWT.NONE);
        GridLayoutFactory.swtDefaults().margins(0, 0).extendedMargins(0, 0, 10, 0).numColumns(3)
                .applyTo(allButtonsComposite);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(allButtonsComposite);

        this.instructionsViewer = new TableViewer(leftPart, SWT.SINGLE | SWT.BORDER);
        this.instructionsViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
        this.instructionsViewer.getTable().setFont(appFont);

        new TableColumn(this.instructionsViewer.getTable(), SWT.NONE);
        TableColumn hiddenAttrColumn = new TableColumn(this.instructionsViewer.getTable(), SWT.NONE);
        hiddenAttrColumn.setWidth(COL_WIDTH);
        hiddenAttrColumn.setResizable(false);
        hiddenAttrColumn.setMoveable(false);

        this.instructionsViewer.setLabelProvider(new ITableLabelProvider() {
            @Override
            public String getColumnText(Object element, int columnIndex) {
                String result = "";
                if (columnIndex == 0 && element != null)
                    result = element.toString();

                return result;
            }

            @Override
            public Image getColumnImage(Object element, int columnIndex) {
                Image result = null;
                if (columnIndex == 0 && element instanceof AddImageInstruction) {
                    String ext = StringUtils.getFileExtension(((AddImageInstruction) element).getImgFile());
                    result = ResourceRegistry.findFileImage(ext);

                } else if (columnIndex == 1 && ((AbstractInstruction) element).isHidden()) {
                    result = ResourceRegistry.ICON_HIDDEN_16x16;
                }

                return result;
            }

            @Override
            public void addListener(ILabelProviderListener arg0) {
                // nothing
            }

            @Override
            public void dispose() {
                // nothing
            }

            @Override
            public boolean isLabelProperty(Object arg0, String arg1) {
                return false;
            }

            @Override
            public void removeListener(ILabelProviderListener arg0) {
                // nothing
            }
        });

        this.instructionsViewer.setContentProvider(new ArrayContentProvider());
        this.instructionsViewer.addDoubleClickListener(new IDoubleClickListener() {
            @Override
            public void doubleClick(DoubleClickEvent e) {
                Object o = ((IStructuredSelection) e.getSelection()).getFirstElement();
                if (o instanceof AddImageInstruction && Desktop.isDesktopSupported()) {

                    File f = ((AddImageInstruction) o).getImgFile();
                    try {
                        Desktop.getDesktop().open(f);
                    } catch (IOException e1) {
                        LogUtils.log("Could not open " + f, e1);
                    }
                }
            }
        });

        this.instructionsViewer.getTable().addControlListener(new ControlAdapter() {
            @Override
            public void controlResized(ControlEvent e) {
                Table table = (Table) e.widget;

                int width = table.getSize().x - 2 * table.getBorderWidth();
                if (table.getVerticalBar().isVisible())
                    width -= table.getVerticalBar().getSize().x;

                width -= COL_WIDTH;
                table.getColumn(0).setWidth(width);
            }
        });

        // Options
        final Group optionsGroup = new Group(leftPart, SWT.SHADOW_ETCHED_IN);
        GridLayoutFactory.swtDefaults().numColumns(2).margins(15, 15).applyTo(optionsGroup);
        GridDataFactory.swtDefaults().align(SWT.FILL, SWT.END).grab(true, false).hint(SWT.DEFAULT, 120)
                .applyTo(optionsGroup);

        optionsGroup.setText("Options");
        optionsGroup.setFont(appFont);
        optionsGroup.setVisible(false);

        // Buttons
        Composite buttonsComposite = new Composite(allButtonsComposite, SWT.NONE);
        GridLayoutFactory.swtDefaults().margins(0, 0).applyTo(buttonsComposite);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonsComposite);

        final Button upButton = new Button(buttonsComposite, SWT.PUSH);
        upButton.setFont(appFont);
        upButton.setText("Haut");
        upButton.setToolTipText("Monter cette instruction d'un cran");
        upButton.setImage(ResourceRegistry.ICON_UP_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(upButton);
        upButton.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                int index = CollageFacet.this.collage.getInstructions().indexOf(o);
                if (index > 0) {
                    CollageFacet.this.collage.getInstructions().remove(o);
                    CollageFacet.this.collage.getInstructions().add(index - 1, (AbstractInstruction) o);
                    refresh();

                    CollageFacet.this.instructionsViewer.setInput(CollageFacet.this.collage.getInstructions());
                    CollageFacet.this.instructionsViewer.refresh();
                }
            }
        });

        final Button downButton = new Button(buttonsComposite, SWT.PUSH);
        downButton.setFont(appFont);
        downButton.setText("Bas");
        downButton.setToolTipText("Baisser cette instruction d'un cran");
        downButton.setImage(ResourceRegistry.ICON_DOWN_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(downButton);
        downButton.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                int index = CollageFacet.this.collage.getInstructions().indexOf(o);
                if (index + 1 < CollageFacet.this.collage.getInstructions().size()) {
                    CollageFacet.this.collage.getInstructions().remove(o);
                    CollageFacet.this.collage.getInstructions().add(index + 1, (AbstractInstruction) o);
                    refresh();

                    CollageFacet.this.instructionsViewer.setInput(CollageFacet.this.collage.getInstructions());
                    CollageFacet.this.instructionsViewer.refresh();
                }
            }
        });

        Button b = new Button(buttonsComposite, SWT.PUSH);
        b.setFont(appFont);
        b.setText("Rafrachir");
        b.setToolTipText("Regnrer le collage");
        b.setImage(ResourceRegistry.ICON_REFRESH_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(b);
        b.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {
                refresh();
            }
        });

        buttonsComposite = new Composite(allButtonsComposite, SWT.NONE);
        GridLayoutFactory.swtDefaults().margins(0, 0).applyTo(buttonsComposite);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonsComposite);

        final Button removeButton = new Button(buttonsComposite, SWT.PUSH);
        removeButton.setFont(appFont);
        removeButton.setText("Supprimer");
        removeButton.setToolTipText("Supprimer cette instruction");
        removeButton.setImage(ResourceRegistry.ICON_DELETE_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(removeButton);
        removeButton.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                if (o instanceof BackgroundInstruction)
                    return;

                CollageFacet.this.collage.getInstructions().remove(o);
                refresh();
                CollageFacet.this.instructionsViewer.remove(o);
            }
        });

        new Label(buttonsComposite, SWT.NONE);

        final Button hideButton = new Button(buttonsComposite, SWT.PUSH);
        hideButton.setFont(appFont);
        hideButton.setText(GHOST_BUTTON_E);
        hideButton.setToolTipText("Dsactiver ou Ractiver cette instruction");
        hideButton.setImage(ResourceRegistry.ICON_GHOST_32x32);
        GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.END).applyTo(hideButton);
        hideButton.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                AbstractInstruction instr = (AbstractInstruction) o;
                if (instr.isRemovable()) {
                    boolean b = !instr.isHidden();
                    instr.setHidden(b);

                    refresh();
                    CollageFacet.this.instructionsViewer.update(instr, null);
                    CollageFacet.this.instructionsViewer.getTable().notifyListeners(SWT.Selection, new Event());
                }
            }
        });

        buttonsComposite = new Composite(allButtonsComposite, SWT.NONE);
        GridLayoutFactory.swtDefaults().margins(0, 0).applyTo(buttonsComposite);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonsComposite);

        b = new Button(buttonsComposite, SWT.PUSH);
        b.setFont(appFont);
        b.setText("Ajout d'Image");
        b.setToolTipText("Ajouter une image");
        b.setImage(ResourceRegistry.ICON_ADD_IMAGE_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(b);
        b.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                int index = -1;
                if (!CollageFacet.this.instructionsViewer.getSelection().isEmpty()) {
                    Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                            .getFirstElement();
                    index = CollageFacet.this.collage.getInstructions().indexOf(o);
                    index++;
                }

                List<File> files = Utils.openImagesSelectionDialog(getShell());
                for (File f : files) {
                    AddImageInstruction instr = new AddImageInstruction();
                    instr.setImgFile(f);

                    if (index == -1) {
                        CollageFacet.this.collage.getInstructions().add(instr);
                        CollageFacet.this.instructionsViewer.add(instr);
                    } else {
                        CollageFacet.this.collage.getInstructions().add(index, instr);
                        CollageFacet.this.instructionsViewer.insert(instr, index);
                    }
                }

                refresh();
            }
        });

        b = new Button(buttonsComposite, SWT.PUSH);
        b.setFont(appFont);
        b.setText("Saut  la Ligne");
        b.setToolTipText("Passer  la ligne");
        b.setImage(ResourceRegistry.ICON_BREAK_LINE_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(b);
        b.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                int index = -1;
                if (!CollageFacet.this.instructionsViewer.getSelection().isEmpty()) {
                    Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                            .getFirstElement();
                    index = CollageFacet.this.collage.getInstructions().indexOf(o);
                    index++;
                }

                BreakLineInstruction instr = new BreakLineInstruction();
                if (index == -1) {
                    CollageFacet.this.collage.getInstructions().add(instr);
                    CollageFacet.this.instructionsViewer.add(instr);
                } else {
                    CollageFacet.this.collage.getInstructions().add(index, instr);
                    CollageFacet.this.instructionsViewer.insert(instr, index);
                }

                refresh();
            }
        });

        b = new Button(buttonsComposite, SWT.PUSH);
        b.setFont(appFont);
        b.setText("Dcalage");
        b.setToolTipText("Rajouter un nouveau bloc");
        b.setImage(ResourceRegistry.ICON_SHIFT_32x32);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(b);
        b.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event event) {

                int index = -1;
                if (!CollageFacet.this.instructionsViewer.getSelection().isEmpty()) {
                    Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                            .getFirstElement();
                    index = CollageFacet.this.collage.getInstructions().indexOf(o);
                    index++;
                }

                ShiftInstruction instr = new ShiftInstruction();
                if (index == -1) {
                    CollageFacet.this.collage.getInstructions().add(instr);
                    CollageFacet.this.instructionsViewer.add(instr);
                } else {
                    CollageFacet.this.collage.getInstructions().add(index, instr);
                    CollageFacet.this.instructionsViewer.insert(instr, index);
                }

                refresh();
            }
        });

        // The right part
        final Composite rightPart = new Composite(this, SWT.NONE);
        GridLayoutFactory.swtDefaults().margins(0, 0).spacing(10, 5).equalWidth(false).applyTo(rightPart);
        GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(rightPart);
        GridDataFactory.swtDefaults().span(3, 1).applyTo(new Label(rightPart, SWT.NONE));

        this.previewCanvas = new ImageCanvas(rightPart, SWT.COLOR_WIDGET_BACKGROUND);
        this.previewCanvas.setShowGhostImage(false);
        GridDataFactory.fillDefaults().grab(true, true).indent(0, 10).applyTo(this.previewCanvas);

        this.previewCanvas.setToolTipText("Double-Cliquez pour lancer en Plein Ecran");
        this.previewCanvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseDoubleClick(MouseEvent e) {
                if (CollageFacet.this.previewImg != null)
                    new StaticImageViewer().open(CollageFacet.this.previewImg);
            }
        });

        this.dimensionsLabel = new Label(rightPart, SWT.NONE);
        this.dimensionsLabel.setFont(appFont);
        GridDataFactory.swtDefaults().grab(true, false).align(SWT.CENTER, SWT.BOTTOM).applyTo(this.dimensionsLabel);

        if (this.collage.getInstructions().size() > 1) {
            this.instructionsViewer.setInput(this.collage.getInstructions());
            refresh();
        }

        // Buttons selection
        this.instructionsViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(SelectionChangedEvent e) {
                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                int index = CollageFacet.this.collage.getInstructions().indexOf(o);
                if (index == -1) {
                    removeButton.setEnabled(false);
                    upButton.setEnabled(false);
                    downButton.setEnabled(false);
                    hideButton.setEnabled(false);

                    hideButton.setText(GHOST_BUTTON_E);
                    hideButton.update();

                } else {
                    upButton.setEnabled(index > 0);
                    downButton.setEnabled(index < CollageFacet.this.collage.getInstructions().size() - 1);

                    removeButton.setEnabled(((AbstractInstruction) o).isRemovable());
                    hideButton.setEnabled(((AbstractInstruction) o).isRemovable());
                    hideButton.setText(((AbstractInstruction) o).isHidden() ? GHOST_BUTTON_D : GHOST_BUTTON_E);
                    hideButton.update();
                }

                updateOptions(o, optionsGroup);
            }
        });

        this.instructionsViewer.getTable().notifyListeners(SWT.Selection, new Event());

        // Add a rename action
        final IAction renameAction = new Action("Renommer l'image...") {
            @Override
            public void run() {
                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                if (!(o instanceof AddImageInstruction))
                    return;

                final File imgFile = ((AddImageInstruction) o).getImgFile();
                if (Utils.openRenameDialog(imgFile, getShell()))
                    CollageFacet.this.instructionsViewer.update(imgFile, null);
            }
        };

        final MenuManager popupMenu = new MenuManager();
        popupMenu.setRemoveAllWhenShown(true);
        popupMenu.addMenuListener(new IMenuListener() {
            @Override
            public void menuAboutToShow(IMenuManager mngr) {
                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                if (o instanceof AddImageInstruction)
                    mngr.add(renameAction);
            }
        });

        Menu menu = popupMenu.createContextMenu(this.instructionsViewer.getTable());
        this.instructionsViewer.getTable().setMenu(menu);

        // Add drag'n'drop support
        Transfer[] transfers = new Transfer[] { TextTransfer.getInstance() };
        int ops = DND.DROP_COPY | DND.DROP_MOVE;
        this.instructionsViewer.addDragSupport(ops, transfers, new DragSourceAdapter() {
            @Override
            public void dragSetData(DragSourceEvent e) {
                if (TextTransfer.getInstance().isSupportedType(e.dataType)) {
                    Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                            .getFirstElement();
                    Integer index = CollageFacet.this.collage.getInstructions().indexOf(o);
                    if (index != -1)
                        e.data = String.valueOf(index);
                }
            }

            @Override
            public void dragStart(DragSourceEvent e) {
                Object o = ((IStructuredSelection) CollageFacet.this.instructionsViewer.getSelection())
                        .getFirstElement();
                e.doit = o instanceof AddImageInstruction || o instanceof BreakLineInstruction
                        || o instanceof ShiftInstruction;
            }
        });

        this.instructionsViewer.addDropSupport(ops, transfers, new ViewerDropAdapter(this.instructionsViewer) {
            @Override
            public boolean validateDrop(Object target, int op, TransferData type) {
                // Do not drop before the background or border instructions
                int index = CollageFacet.this.collage.getInstructions().indexOf(target);
                return index > 1 && TextTransfer.getInstance().isSupportedType(type);
            }

            @Override
            public boolean performDrop(Object data) {
                AbstractInstruction instr = (AbstractInstruction) getCurrentTarget();
                int index = CollageFacet.this.collage.getInstructions().indexOf(instr);

                boolean result = false;
                int movedIndex = Integer.parseInt((String) getCurrentEvent().data);
                AbstractInstruction movedInstr = CollageFacet.this.collage.getInstructions().remove(movedIndex);
                if (movedInstr != null) {
                    result = true;
                    CollageFacet.this.collage.getInstructions().add(index, movedInstr);
                    CollageFacet.this.instructionsViewer.refresh();
                    refresh();
                }

                return result;
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see net.leboxondelex.daplomb.ui.facets.ApplicationFacet
     * #registerFileMenus(org.eclipse.swt.widgets.Menu)
     */
    @Override
    public void registerFileMenus(Menu fileMenu) {

        MenuItem item = new MenuItem(fileMenu, SWT.PUSH, 0);
        item.setText("Nouveau");
        item.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event e) {

                if (CollageFacet.this.collage.getInstructions().size() > 1) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("Le collage actuel va tre effac. Voulez-vous continuer ?");
                    boolean goOn = Utils.showQuestion(getShell(), "Confirmation", sb.toString());
                    if (!goOn)
                        return;
                }

                CollageFacet.this.collage = new Collage();
                CollageFacet.this.collageBuilder = new CollageBuilder(CollageFacet.this.collage);
                refresh();

                CollageFacet.this.instructionsViewer.setInput(CollageFacet.this.collage.getInstructions());
                CollageFacet.this.instructionsViewer.refresh();
            }
        });

        item = new MenuItem(fileMenu, SWT.PUSH, 1);
        item.setText("Ouvrir...");
        item.addListener(SWT.Selection, new Listener() {
            @Override
            public void handleEvent(Event e) {
                String fn = openCollageDialog(false, true);
                if (fn == null)
                    return;

                try {
                    CollageFacet.this.collage = CollageIO.readCollage(new File(fn));
                    CollageFacet.this.collageBuilder = new CollageBuilder(CollageFacet.this.collage);
                    refresh();

                    CollageFacet.this.instructionsViewer.setInput(CollageFacet.this.collage.getInstructions());
                    CollageFacet.this.instructionsViewer.refresh();

                } catch (IOException e1) {
                    LogUtils.log(e1);
                }
            }
        });

        int index = 2;
        if (this.collage != null) {
            index = 5;

            item = new MenuItem(fileMenu, SWT.PUSH, 2);
            item.setText("Enregistrer l'Image...");
            item.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    String fn = openCollageDialog(true, false);
                    if (fn != null)
                        ImageUtils.saveAssemblyImage(CollageFacet.this.previewImg, new File(fn));
                }
            });

            item = new MenuItem(fileMenu, SWT.PUSH, 3);
            item.setText("Enregistrer la Source...");
            item.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    String fn = openCollageDialog(true, true);
                    if (fn == null)
                        return;

                    try {
                        CollageIO.saveCollage(CollageFacet.this.collage, new File(fn));

                    } catch (IOException e1) {
                        LogUtils.log(e1);
                    }
                }
            });

            item = new MenuItem(fileMenu, SWT.PUSH, 4);
            item.setText("Enregistrer dans la Bibliothque...");
            item.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {

                    File libDirectory = PreferencesManager.INSTANCE.getLibraryRootDirectory();
                    final File collageDirectory = new File(libDirectory, COLLAGES_DIR);
                    if (!collageDirectory.exists() && !collageDirectory.mkdirs()) {
                        LogUtils.log("Could not create the 'collages' directory in the library.");
                        Utils.showError(getShell(), "Erreurr",
                                "Le collage n'a pas pu tre sauvegard dans la bibliothque.");
                        return;
                    }

                    InputDialog dlg = new InputDialog(getShell(), "Nom du Collage", "Indiquez le nom du collage.",
                            "", new IInputValidator() {
                                @Override
                                public String isValid(String s) {

                                    if (StringUtils.isEmpty(s))
                                        return "Spcifiez un nom de fichier valide.";

                                    if (new File(collageDirectory, s + Utils.IMG_SUFFIX).exists())
                                        return "Ce nom est dj utilis par un autre fichier.";

                                    return null;
                                }
                            });

                    if (dlg.open() != Window.OK)
                        return;

                    String s = dlg.getValue();
                    try {
                        File f = new File(collageDirectory, s + Utils.IMG_SUFFIX);
                        ImageUtils.saveAssemblyImage(CollageFacet.this.previewImg, f);

                        f = new File(collageDirectory, s + ".collage");
                        CollageIO.saveCollage(CollageFacet.this.collage, f);

                    } catch (IOException e1) {
                        LogUtils.log(e1);
                    }
                }
            });
        }

        new MenuItem(fileMenu, SWT.SEPARATOR, index);
    }

    /*
     * (non-Javadoc)
     * @see net.leboxondelex.daplomb.ui.facets.ApplicationFacet
     * #onDispose()
     */
    @Override
    protected void onDispose() {
        if (this.previewImg != null)
            this.previewImg.dispose();

        if (this.collage.getInstructions().size() > 0) {
            try {
                CollageIO.saveCollage(this.collage, this.backupFile);

            } catch (IOException e) {
                LogUtils.log(e);
            }
        }
    }

    /**
     * Refreshes the collage preview.
     */
    private void refresh() {
        this.collageBuilder.refresh();
        this.previewImg = this.collageBuilder.getAssembly();
        this.previewCanvas.setImage(this.previewImg);

        StringBuilder sb = new StringBuilder(DIM);
        sb.append(" ");
        sb.append(this.previewImg.getImageDimensions().x);
        sb.append(" x ");
        sb.append(this.previewImg.getImageDimensions().y);

        this.dimensionsLabel.setText(sb.toString());
        this.dimensionsLabel.getParent().layout();
    }

    /**
     * Opens a collage dialog.
     * @param save true for a save dialog
     * @return the file path, or null if 'cancel' was pressed
     */
    private String openCollageDialog(boolean save, boolean source) {
        int style = save ? SWT.SAVE : SWT.OPEN;
        FileDialog dlg = new FileDialog(getShell(), style);
        if (save)
            dlg.setOverwrite(true);

        if (source) {
            File fl = new File(PreferencesManager.INSTANCE.getLibraryRootDirectory(), COLLAGES_DIR);
            if (fl.exists())
                dlg.setFilterPath(fl.getAbsolutePath());

            dlg.setFilterExtensions(new String[] { "*.collage" });
            dlg.setFilterNames(new String[] { "Collage" });
        } else {
            dlg.setFilterExtensions(new String[] { "*.jpg" });
            dlg.setFilterNames(new String[] { "JPG" });
        }

        return dlg.open();
    }

    /**
     * Updates the options area.
     * @param o
     * @param optionsGroup
     */
    private void updateOptions(Object o, Group optionsGroup) {

        // Remove the options
        for (Control c : optionsGroup.getChildren()) {
            if (!c.isDisposed())
                c.dispose();
        }

        // Populate the options
        boolean visible = false;

        // Break Line
        if (o instanceof BreakLineInstruction) {
            final BreakLineInstruction instr = (BreakLineInstruction) o;
            visible = true;

            Label l = new Label(optionsGroup, SWT.NONE);
            l.setText("Epaisseur du Saut de Ligne :");
            l.setFont(this.appFont);

            Spinner spinner = new Spinner(optionsGroup, SWT.BORDER);
            spinner.setFont(this.appFont);
            GridDataFactory.swtDefaults().hint(100, SWT.DEFAULT).applyTo(spinner);
            spinner.setValues(instr.getSize(), 0, Integer.MAX_VALUE, 0, 1, 10);
            spinner.addListener(SWT.Modify, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    int size = ((Spinner) e.widget).getSelection();
                    instr.setSize(size);
                    refresh();
                }
            });
        }

        // Add Image
        else if (o instanceof AddImageInstruction) {
            final AddImageInstruction instr = (AddImageInstruction) o;
            visible = true;

            final Button hMirrorButton = new Button(optionsGroup, SWT.CHECK);
            hMirrorButton.setFont(this.appFont);
            GridDataFactory.swtDefaults().span(2, 1).applyTo(hMirrorButton);
            hMirrorButton.setText("Miroir Horizontal");
            hMirrorButton.setSelection(instr.isFlipHorizontally());
            hMirrorButton.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    boolean enabled = ((Button) e.widget).getSelection();
                    instr.setFlipHorizontally(enabled);

                    if (instr.getCropArea() != null) {
                        ImageData imgData = new ImageData(instr.getImgFile().getAbsolutePath());
                        if (imgData.width != instr.getCropArea().width) {
                            int newX = imgData.width - instr.getCropArea().x - instr.getCropArea().width;
                            instr.getCropArea().x = newX;
                        }
                    }

                    refresh();
                }
            });

            final Button vMirrorButton = new Button(optionsGroup, SWT.CHECK);
            vMirrorButton.setFont(this.appFont);
            GridDataFactory.swtDefaults().span(2, 1).applyTo(vMirrorButton);
            vMirrorButton.setText("Miroir Vertical");
            vMirrorButton.setSelection(instr.isFlipVertically());
            vMirrorButton.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    boolean enabled = ((Button) e.widget).getSelection();
                    instr.setFlipVertically(enabled);

                    if (instr.getCropArea() != null) {
                        ImageData imgData = new ImageData(instr.getImgFile().getAbsolutePath());
                        if (imgData.height != instr.getCropArea().height) {
                            int newY = imgData.height - instr.getCropArea().y - instr.getCropArea().height;
                            instr.getCropArea().y = newY;
                        }
                    }

                    refresh();
                }
            });

            Link editLink = new Link(optionsGroup, SWT.PUSH);
            editLink.setFont(this.appFont);
            GridDataFactory.swtDefaults().span(2, 1).applyTo(editLink);
            editLink.setText("<a>Recadrer l'Image</a>");
            editLink.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {

                    ImageData imgData = new ImageData(instr.getImgFile().getAbsolutePath());
                    ;
                    if (instr.isFlipHorizontally())
                        imgData = ImageUtils.flip(imgData, false);
                    if (instr.isFlipVertically())
                        imgData = ImageUtils.flip(imgData, true);

                    CropImageDialog dlg = new CropImageDialog(getShell(), imgData, instr.getCropArea(), null);

                    if (dlg.open() == Window.OK) {
                        instr.setCropArea(dlg.getRectangle());
                        refresh();
                    }
                }
            });
        }

        // Borders
        else if (o instanceof BordersInstruction) {
            final BordersInstruction instr = (BordersInstruction) o;
            visible = true;

            Label l = new Label(optionsGroup, SWT.NONE);
            l.setText("Bordure Haut/Bas :");
            l.setFont(this.appFont);

            Spinner spinner = new Spinner(optionsGroup, SWT.BORDER);
            spinner.setFont(this.appFont);
            GridDataFactory.swtDefaults().hint(100, SWT.DEFAULT).applyTo(spinner);
            spinner.setValues(instr.getTopDownBorder(), 0, Integer.MAX_VALUE, 0, 1, 10);
            spinner.addListener(SWT.Modify, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    int size = ((Spinner) e.widget).getSelection();
                    instr.setTopDownBorder(size);
                    refresh();
                }
            });

            l = new Label(optionsGroup, SWT.NONE);
            l.setText("Bordure Droite/Gauche :");
            l.setFont(this.appFont);

            spinner = new Spinner(optionsGroup, SWT.BORDER);
            spinner.setFont(this.appFont);
            GridDataFactory.swtDefaults().hint(100, SWT.DEFAULT).applyTo(spinner);
            spinner.setValues(instr.getLeftRightBorder(), 0, Integer.MAX_VALUE, 0, 1, 10);
            spinner.addListener(SWT.Modify, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    int size = ((Spinner) e.widget).getSelection();
                    instr.setLeftRightBorder(size);
                    refresh();
                }
            });

            l = new Label(optionsGroup, SWT.NONE);
            l.setText("Marge Interne Verticale :");
            l.setFont(this.appFont);

            spinner = new Spinner(optionsGroup, SWT.BORDER);
            spinner.setFont(this.appFont);
            GridDataFactory.swtDefaults().hint(100, SWT.DEFAULT).applyTo(spinner);
            spinner.setValues(instr.getHorizontalMargin(), 0, Integer.MAX_VALUE, 0, 1, 10);
            spinner.addListener(SWT.Modify, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    int size = ((Spinner) e.widget).getSelection();
                    instr.setHorizontalMargin(size);
                    refresh();
                }
            });
        }

        // Background
        else if (o instanceof BackgroundInstruction) {
            final BackgroundInstruction instr = (BackgroundInstruction) o;
            visible = true;

            Link editLink = new Link(optionsGroup, SWT.PUSH);
            editLink.setFont(this.appFont);
            GridDataFactory.swtDefaults().span(2, 1).applyTo(editLink);
            editLink.setText("<a>Changer la Couleur de Fond</a>");
            editLink.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    ColorDialog dlg = new ColorDialog(getShell());
                    if (instr.getBgColor() != null)
                        dlg.setRGB(instr.getBgColor());

                    RGB rgb = dlg.open();
                    if (rgb != null) {
                        instr.setBgColor(rgb);
                        refresh();
                    }
                }
            });

            final Button transparentButton = new Button(optionsGroup, SWT.CHECK);
            transparentButton.setFont(this.appFont);
            GridDataFactory.swtDefaults().span(2, 1).applyTo(transparentButton);
            transparentButton.setText("Fond Transparent");
            transparentButton.setSelection(instr.isTransparentBg());
            transparentButton.addListener(SWT.Selection, new Listener() {
                @Override
                public void handleEvent(Event e) {
                    boolean enabled = ((Button) e.widget).getSelection();
                    instr.setTransparentBg(enabled);
                    instr.setBgColor(null);
                    refresh();
                }
            });
        }

        // Update the visibility
        optionsGroup.layout();
        optionsGroup.setVisible(visible);
    }
}