/*
* Copyright (c) 1998-2017 by Richard A. Wilkes. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, version 2.0. If a copy of the MPL was not distributed with
* this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This Source Code Form is "Incompatible With Secondary Licenses", as
* defined by the Mozilla Public License, version 2.0.
*/
package com.trollworks.gcs.widgets.outline;
import com.trollworks.gcs.common.DataFile;
import com.trollworks.gcs.common.LoadState;
import com.trollworks.toolkit.annotation.Localize;
import com.trollworks.toolkit.io.xml.XMLNodeType;
import com.trollworks.toolkit.io.xml.XMLReader;
import com.trollworks.toolkit.io.xml.XMLWriter;
import com.trollworks.toolkit.utility.Localization;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
/** An undo for the entire row, with the exception of its children. */
public class RowUndo extends AbstractUndoableEdit {
@Localize("{0} Changes")
@Localize(locale = "de", value = "{0} Änderungen")
@Localize(locale = "ru", value = "{0} изменений")
@Localize(locale = "es", value = "{0} Cambios")
private static String UNDO_FORMAT;
static {
Localization.initialize();
}
private DataFile mDataFile;
private ListRow mRow;
private String mName;
private byte[] mBefore;
private byte[] mAfter;
/**
* Creates a new {@link RowUndo}.
*
* @param row The row being undone.
*/
public RowUndo(ListRow row) {
super();
mRow = row;
mDataFile = mRow.getDataFile();
mName = MessageFormat.format(UNDO_FORMAT, mRow.getLocalizedName());
mBefore = serialize(mRow);
}
/**
* Call to finish capturing the undo state.
*
* @return <code>true</code> if there is a difference between the before and after state.
*/
public boolean finish() {
mAfter = serialize(mRow);
if (mBefore.length != mAfter.length) {
return true;
}
for (int i = 0; i < mBefore.length; i++) {
if (mBefore[i] != mAfter[i]) {
return true;
}
}
return false;
}
private static byte[] serialize(ListRow row) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gos = new GZIPOutputStream(baos);
try (XMLWriter writer = new XMLWriter(gos)) {
row.save(writer, true);
}
return baos.toByteArray();
} catch (Exception exception) {
exception.printStackTrace(System.err);
}
return new byte[0];
}
private void deserialize(byte[] buffer) {
try (XMLReader reader = new XMLReader(new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(buffer))))) {
XMLNodeType type = reader.next();
LoadState state = new LoadState();
state.mForUndo = true;
while (type != XMLNodeType.END_DOCUMENT) {
if (type == XMLNodeType.START_TAG) {
mRow.load(reader, state);
type = reader.getType();
} else {
type = reader.next();
}
}
} catch (Exception exception) {
exception.printStackTrace(System.err);
}
}
@Override
public void undo() throws CannotUndoException {
super.undo();
deserialize(mBefore);
}
@Override
public void redo() throws CannotRedoException {
super.redo();
deserialize(mAfter);
}
/** @return The {@link DataFile} this undo works on. */
public DataFile getDataFile() {
return mDataFile;
}
/** @return The row this undo works on. */
public ListRow getRow() {
return mRow;
}
@Override
public String getPresentationName() {
return mName;
}
}