/*
* 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.Drawable;
import pixelitor.selection.IgnoreSelection;
import pixelitor.utils.debug.DebugNode;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import java.awt.image.BufferedImage;
import java.lang.ref.SoftReference;
import static pixelitor.Composition.ImageChangeActions.FULL;
/**
* A PixelitorEdit that represents the changes made to an image.
*/
public class ImageEdit extends FadeableEdit {
private final IgnoreSelection ignoreSelection;
private SoftReference<BufferedImage> imgRef;
protected Drawable dr;
private final boolean canRepeat;
public ImageEdit(Composition comp, String name, Drawable dr,
BufferedImage backupImage,
IgnoreSelection ignoreSelection, boolean canRepeat) {
super(comp, dr, name);
this.ignoreSelection = ignoreSelection;
assert dr != null;
assert backupImage != null;
// the backup image is stored in an SoftReference
this.imgRef = new SoftReference<>(backupImage);
this.dr = dr;
this.canRepeat = canRepeat;
checkBackupDifferentFromActive();
}
private void checkBackupDifferentFromActive() {
// the backup should never be identical to the active image
// otherwise the backup might be also edited
BufferedImage layerImage = dr.getImage();
if (layerImage == imgRef.get()) {
throw new IllegalStateException("backup BufferedImage is identical to the active one");
}
}
@Override
public void undo() throws CannotUndoException {
super.undo();
if (!swapImages()) {
throw new CannotUndoException();
}
}
@Override
public void redo() throws CannotRedoException {
super.redo();
if (!swapImages()) {
throw new CannotRedoException();
}
}
/**
* Returns true if successful
*/
private boolean swapImages() {
BufferedImage backupImage = imgRef.get();
if(backupImage == null) {
return false;
}
BufferedImage tmp;
if(ignoreSelection.isYes()) {
tmp = dr.getImage();
} else {
tmp = dr.getImageOrSubImageIfSelected(false, true);
}
dr.changeImageUndoRedo(backupImage, ignoreSelection);
// create new backup image from tmp
imgRef = new SoftReference<>(tmp);
if(!embedded) {
comp.imageChanged(FULL);
dr.updateIconImage();
History.notifyMenus(this);
}
checkBackupDifferentFromActive();
return true;
}
@Override
public void die() {
super.die();
BufferedImage backupImage = imgRef.get();
if(backupImage != null) {
backupImage.flush();
}
imgRef = null;
dr = null;
}
@Override
public BufferedImage getBackupImage() {
if(imgRef != null) {
// this still could be null
return imgRef.get();
}
return null;
}
@Override
public boolean canRepeat() {
return canRepeat;
}
@Override
public DebugNode getDebugNode() {
DebugNode node = super.getDebugNode();
BufferedImage img = imgRef.get();
if (img != null) {
node.addIntChild("Backup Image Width", img.getWidth());
node.addIntChild("Backup Image Height", img.getHeight());
}
return node;
}
}