/******************************************************************************* * Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Thomas Holland - initial API and implementation *******************************************************************************/ package de.innot.avreclipse.core.toolinfo.fuses; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.ui.console.IOConsoleOutputStream; import org.eclipse.ui.console.MessageConsole; import de.innot.avreclipse.core.util.AVRMCUidConverter; /** * This class contains the results from a {@link ByteValues} conversion from one MCU to another. * <p> * It maintains three lists of {@link BitFieldDescription} objects: * <ul> * <li>BitFields successfully converted (<em>Success</em></li> * <li>BitFields from the source that had no match in the target mcu (<em>NotCopied</em>)</li> * <li>Bitfields in the target that had no corresponding BitField in the source (<em>UnSet</em>)</li> * </ul> * Currently there are only three public methods:</br> {@link #getStatusForName(String)} returns * the {@link ConversionStatus} for the BitField with a given name.</br> * {@link #printToConsole(MessageConsole)} dumps the result of the conversion in a human readable * format to the given Console.</br> {@link #getSuccessRate()} returns how successful the * conversion was as a percentage.</br> * </p> * <p> * To use this class instantiate it and pass the new object to the * {@link ByteValues#convertTo(String, ConversionResults)} method. * </p> * <p> * Objects of this class can be reused, as all parameters will be cleared once it is passed to the * <code>ByteValues.convertTo()</code> method. * </p> * <p> * This class is <strong>not</strong> thread safe. It should not be accessed while the conversion * is still running. * </p> * * @author Thomas Holland * @since 2.3 * */ public class ConversionResults { /** * An enumeration of conversion results for a single BitField. * * @see ConversionResults#getStatusForName(String); */ public enum ConversionStatus { /** BitField has not been converted. This is the default if no conversion has taken place yet */ NO_CONVERSION, /** BitField successfully converted, value text identical. */ SUCCESS, /** BitField successfully converted, value text differs between source and target. */ VALUE_CHANGED, /** * Target BitField was set to the default value, because there was no matching BitField in * the Source. */ NOT_IN_SOURCE, /** Source BitField was not copied because there was no matching BitField in the target. */ NOT_IN_TARGET, /** * A new value has been assigned to the BitField (presumably by the user and he has * recognized the status). */ MODIFIED, /** Status is unknown. The BitField name was not in any of the three lists. */ UNKNOWN; } /** List of all BitFields successfully copied. */ private final List<BitFieldDescription> fSuccessList = new ArrayList<BitFieldDescription>(); /** List of all BitFields from the source, that have no match in the target. */ private final List<BitFieldDescription> fNotCopiedList = new ArrayList<BitFieldDescription>(); /** List of all BitFields in the target, that have no match in the source. */ private final List<BitFieldDescription> fUnsetFieldsList = new ArrayList<BitFieldDescription>(); /** List of all BitFields in the target that have been modified since the last conversion. */ private final List<String> fModifiedList = new ArrayList<String>(); /** The source <code>ByteValues</code>. */ private ByteValues fSource = null; /** The target <code>ByteValues</code>. */ private ByteValues fTarget = null; /** Internal flag to indicate that the conversion is complete. */ private boolean fReady = false; /** * Called by {@link ByteValues#convertTo(String, ConversionResults)} to initialize the results. * * @param source * The source <code>ByteValues</code> for the conversion. * @param target * The target <code>ByteValues</code> for the conversion. */ protected void init(ByteValues source, ByteValues target) { fSource = source; fTarget = target; fSuccessList.clear(); fNotCopiedList.clear(); fNotCopiedList.clear(); fNotCopiedList.addAll(fSource.getBitfieldDescriptions()); } /** * Called by {@link ByteValues#convertTo(String, ConversionResults)} to add a successful * BitField conversion to the list. * * @param desc * <code>BitFieldDescription</code> */ protected void addSuccess(BitFieldDescription desc) { fSuccessList.add(desc); } /** * Called by {@link ByteValues#convertTo(String, ConversionResults)} to remove a source BitField * which could not be converted. * * @param desc * <code>BitFieldDescription</code> */ protected void removeNotCopied(BitFieldDescription desc) { fNotCopiedList.remove(desc); } /** * Called by {@link ByteValues#convertTo(String, ConversionResults)} to add a target BitField * which was set to the default value. * * @param desc * <code>BitFieldDescription</code> */ protected void addUnset(BitFieldDescription desc) { fUnsetFieldsList.add(desc); } /** * Called by {@link ByteValues#convertTo(String, ConversionResults)} to indicate that the * conversion has finished. * <p> * Currently unused but might be used in the future to implement a threat safe access to this * class. * </p> * */ protected void setReady() { fReady = true; } /** * Adds a BitField name to the list of bitfields that have been modified since the last * conversion. * <p> * {@link #getStatusForName(String)} will return {@link ConversionStatus#MODIFIED} for these * fields. * </p> * * @param name * The name of a BitField. Ignored if <code>null</code> */ protected void setModified(String name) { if (name != null) { fModifiedList.add(name); } } /** * Get the {@link ConversionStatus} for the BitField with the given name. * * @param name * The name of a BitField. * @return The conversion status for the BitField with the given name. */ public ConversionStatus getStatusForName(String name) { for (String bitfieldname : fModifiedList) { if (bitfieldname.equals(name)) { return ConversionStatus.MODIFIED; } } for (BitFieldDescription bfd : fSuccessList) { if (bfd.getName().equals(name)) { // Check if the value text has changed String oldvalue = fSource.getNamedValueText(name); String newvalue = fTarget.getNamedValueText(name); if (oldvalue.equals(newvalue)) { return ConversionStatus.SUCCESS; } return ConversionStatus.VALUE_CHANGED; } } for (BitFieldDescription bfd : fNotCopiedList) { if (bfd.getName().equals(name)) { return ConversionStatus.NOT_IN_TARGET; } } for (BitFieldDescription bfd : fUnsetFieldsList) { if (bfd.getName().equals(name)) { return ConversionStatus.NOT_IN_SOURCE; } } return ConversionStatus.UNKNOWN; } /** * Dump the results of the conversion in a human readable form to a console. * <p> * The console is automatically moved to the front. * </p> * * @param console * Eclipse <code>MessageConsole</code> */ public void printToConsole(final MessageConsole console) { if (!fReady) { // The conversion is not yet finished // TODO: throw an Exception return; } Job consoleoutputjob = new Job("Console output") { @Override public IStatus run(IProgressMonitor monitor) { try { IOConsoleOutputStream iocos = console.newOutputStream(); iocos.setActivateOnWrite(true); iocos.write("----------------------------------------\n"); String sourcemcuname = AVRMCUidConverter.id2name(fSource.getMCUId()); String targetmcuname = AVRMCUidConverter.id2name(fTarget.getMCUId()); String message = MessageFormat.format( "Converting {0} Bytes from {1} MCU to the new project MCU {2}.\n", fSource.getType().toString(), sourcemcuname, targetmcuname); iocos.write(message); iocos.write("Successfully converted fields:\n"); if (fSuccessList.size() == 0) { iocos.write("\tnone!\n"); } else { for (BitFieldDescription bfd : fSuccessList) { String name = bfd.getName(); iocos.write("\t" + name + "\t" + bfd.getDescription() + "\n"); iocos .write("\t\told value: " + fSource.getNamedValueText(name) + "\n"); iocos .write("\t\tnew value: " + fTarget.getNamedValueText(name) + "\n"); } } iocos.write("\n"); message = MessageFormat .format("Fields not converted (a {0} MCU does not have them):\n", targetmcuname); iocos.write(message); if (fNotCopiedList.size() == 0) { iocos.write("\tnone!\n"); } else { for (BitFieldDescription bfd : fNotCopiedList) { String name = bfd.getName(); iocos.write("\t" + name + "\t" + bfd.getDescription() + "\n"); iocos .write("\t\told value: " + fSource.getNamedValueText(name) + "\n"); } } iocos.write("\n"); message = MessageFormat.format( "Fields not set (a {0} MCU does not have them):\n", sourcemcuname); iocos.write(message); if (fUnsetFieldsList.size() == 0) { iocos.write("\tnone!\n"); } else { for (BitFieldDescription bfd : fUnsetFieldsList) { String name = bfd.getName(); iocos.write("\t" + name + "\t" + bfd.getDescription() + "\n"); iocos.write("\t\tdefault value: " + fTarget.getNamedValueText(name) + "\n"); } } iocos.write("\n"); int successrate = getSuccessRate(); message = MessageFormat.format("Conversion {0}% successfull\n", successrate); iocos.write(message); message = MessageFormat.format("Please check the new {0} settings.\n" + "Some bits might have a slightly different meaning for a {1} MCU\n" + "than they had on a {2} MCU.\n", fSource.getType().toString(), targetmcuname, sourcemcuname); iocos.write(message); iocos.flush(); iocos.close(); } catch (IOException e) { } finally { monitor.done(); } return Status.OK_STATUS; } }; consoleoutputjob.setPriority(Job.SHORT); consoleoutputjob.setSystem(true); consoleoutputjob.schedule(); } /** * Get the successrate for the conversion. * <p> * The successrate is determined as the ratio of successful BitField conversions to the total of * all (unique) BitFields form the source and the target. * </p> * <p> * <code>100%</code> means all BitFields have been successfully converted 1 to 1.<br> * <code>0%</code> means that not a single BitField could be converted. * </p> * * @return <code>int</code> between 0 and 100 (%). */ public int getSuccessRate() { int successsize = fSuccessList.size(); int notcopiedsize = fNotCopiedList.size(); int unsetsize = fUnsetFieldsList.size(); int successrate = 100 - (((notcopiedsize + unsetsize) * 100) / (successsize + notcopiedsize + unsetsize)); return successrate; } }