/*
* Copyright 2017 Laszlo Balazs-Csiki
*
* This file is part of Pixelitor. Pixelitor is free software: you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License, version 3 as published by the Free
* Software Foundation.
*
* Pixelitor 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 Pixelitor. If not, see <http://www.gnu.org/licenses/>.
*/
package pixelitor.history;
import pixelitor.Composition;
import pixelitor.layers.ImageLayer;
import pixelitor.layers.Layer;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import java.awt.image.BufferedImage;
import static pixelitor.Composition.ImageChangeActions.FULL;
/**
* A PixelitorEdit representing an operation that can affect multiple layers,
* such as resize, a crop, flip, or image rotation.
* These are undoable only if the composition has a single layer
*/
public class MultiLayerEdit extends PixelitorEdit {
private Layer layer;
private ImageEdit imageEdit;
private CanvasChangeEdit canvasChangeEdit;
private TranslationEdit translationEdit;
private SelectionChangeEdit selectionChangeEdit;
private DeselectEdit deselectEdit;
private final boolean undoable;
public MultiLayerEdit(Composition comp, String name, MultiLayerBackup backup) {
super(comp, name);
int numLayers = comp.getNumLayers();
if (numLayers == 1) {
undoable = true;
layer = comp.getLayer(0);
} else {
undoable = false;
}
if(undoable) {
this.canvasChangeEdit = backup.getCanvasChangeEdit();
this.translationEdit = backup.getTranslationEdit();
BufferedImage maskImage = null;
if (layer.hasMask()) {
maskImage = layer.getMask().getImage();
}
if(layer instanceof ImageLayer) {
ImageLayer imageLayer = (ImageLayer) layer;
BufferedImage layerImage = imageLayer.getImage();
imageEdit = backup.createImageEdit(layerImage, maskImage);
} else if(layer.hasMask()){
// if we have a text layer with a mask, we can still
// create an ImageEdit for the mask
imageEdit = backup.createImageEditForMaskOnly(maskImage);
}
}
if (comp.hasSelection()) {
assert backup.hasSavedSelection();
selectionChangeEdit = backup.createSelectionChangeEdit();
} else {
if (backup.hasSavedSelection()) {
// it was a deselect:
// either a selection crop or a crop tool crop without
// overlap with the existing selection.
deselectEdit = backup.createDeselectEdit();
}
}
}
@Override
public boolean canUndo() {
if (!undoable) {
return false;
}
return super.canUndo();
}
@Override
public boolean canRedo() {
if (!undoable) {
return false;
}
return super.canRedo();
}
@Override
public void undo() throws CannotUndoException {
super.undo();
try {
doTheUndo();
} catch (Exception e) {
dumpState();
throw e;
}
updateGUI();
}
@Override
public void redo() throws CannotRedoException {
super.redo();
try {
doTheRedo();
} catch (Exception e) {
dumpState();
throw e;
}
updateGUI();
}
private void doTheUndo() {
if(imageEdit != null) {
imageEdit.undo();
}
if (translationEdit != null) {
translationEdit.undo();
}
// it is important to undo the canvas change edit
// after the image and translation edits because
// of the image covers canvas checks
if (canvasChangeEdit != null) {
canvasChangeEdit.undo();
}
if (selectionChangeEdit != null) {
selectionChangeEdit.undo();
}
if (deselectEdit != null) {
deselectEdit.undo();
}
}
private void doTheRedo() {
if(imageEdit != null) {
imageEdit.redo();
}
if (translationEdit != null) {
translationEdit.redo();
}
// it is important to redo the canvas change edit
// after the image and translation edits because
// of the image covers canvas checks
if (canvasChangeEdit != null) {
canvasChangeEdit.redo();
}
if (selectionChangeEdit != null) {
selectionChangeEdit.redo();
}
if (deselectEdit != null) {
deselectEdit.redo();
}
}
private void dumpState() {
System.out.printf("MultiLayerEdit:EXCEPTION getName() = '%s'%n", getName());
}
private void updateGUI() {
comp.imageChanged(FULL, true);
if(layer instanceof ImageLayer) {
((ImageLayer)layer).updateIconImage();
}
if (layer.hasMask()) {
layer.getMask().updateIconImage();
}
History.notifyMenus(this);
}
@Override
public void die() {
super.die();
if (imageEdit != null) {
imageEdit.die();
}
if (translationEdit != null) {
translationEdit.die();
}
if (canvasChangeEdit != null) {
canvasChangeEdit.die();
}
if (selectionChangeEdit != null) {
selectionChangeEdit.die();
}
if (deselectEdit != null) {
deselectEdit.die();
}
}
}