/******************************************************************************* * 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.ui.propertypages; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.ErrorDialog; import org.osgi.service.prefs.BackingStoreException; import de.innot.avreclipse.AVRPlugin; import de.innot.avreclipse.core.avrdude.ProgrammerConfig; import de.innot.avreclipse.core.avrdude.ProgrammerConfigManager; import de.innot.avreclipse.core.properties.AVRDudeProperties; import de.innot.avreclipse.core.properties.AVRProjectProperties; import de.innot.avreclipse.core.toolinfo.AVRDude; /** * Extends {@link AbstractAVRPropertyTab} to manage the list of {@link ProgrammerConfig} objects. * <p> * All Tabs requiring direct access to avrdude should extend this class to get a valid * ProgrammerConfig to pass to the {@link AVRDude} action methods. * </p> * * @author Thomas Holland * @since 2.2 */ public abstract class AbstractAVRDudePropertyTab extends AbstractAVRPropertyTab { /** The list of all new or edited {@link ProgrammerConfig} objects */ private final Map<String, ProgrammerConfig> fModifiedProgCfgs = new HashMap<String, ProgrammerConfig>(); /** The list of all current Programmer Config Ids */ private Map<String, String> fProgCfgIDs = new HashMap<String, String>(); protected final static ProgrammerConfigManager fCfgManager = ProgrammerConfigManager .getDefault(); /* * (non-Javadoc) * * @see de.innot.avreclipse.ui.propertypages.AbstractAVRPropertyTab#performApply(de.innot.avreclipse.core.properties.AVRProjectProperties) */ @Override protected void performApply(AVRProjectProperties dst) { // Get the AVRDude Properties and pass it to the subclass AVRDudeProperties avrdudeprops = dst.getAVRDudeProperties(); performApply(avrdudeprops); } abstract protected void performApply(AVRDudeProperties dstprops); /* * (non-Javadoc) * * @see de.innot.avreclipse.ui.propertypages.AbstractAVRPropertyTab#performCopy(de.innot.avreclipse.core.preferences.AVRProjectProperties) */ @Override protected void performCopy(AVRProjectProperties src) { // Get the AVRDude Properties and pass it to the subclass AVRDudeProperties avrdudeprops = src.getAVRDudeProperties(); performCopy(avrdudeprops); // Update the avrdude command preview. updateAVRDudePreview(avrdudeprops); } abstract protected void performCopy(AVRDudeProperties srcprops); /* * (non-Javadoc) * * @see de.innot.avreclipse.ui.propertypages.AbstractAVRPropertyTab#updateData(de.innot.avreclipse.core.preferences.AVRProjectProperties) */ @Override protected void updateData(AVRProjectProperties props) { // Get the AVRDude Properties and pass it to the subclass AVRDudeProperties avrdudeprops = props.getAVRDudeProperties(); updateData(avrdudeprops); // Update the avrdude command preview. updateAVRDudePreview(props.getAVRDudeProperties()); } abstract protected void updateData(AVRDudeProperties avrdudeprops); /* * (non-Javadoc) * * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performOK() */ @Override protected void performOK() { // Save all new / modified programmer configurations saveProgrammerConfigs(); // The saving of the modified avrdude properties is done by the caller } /* * (non-Javadoc) * * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performCancel() */ @Override protected void performCancel() { // remove all modified programmer configurations. // This is probably not necessary, as the field is not static and // after a cancel this tab is disposed. // But just to be sure... fModifiedProgCfgs.clear(); } /** * Get the ID of the ProgrammerConfig for the given name. * * @param name * <code>String</code> with the name * @return <code>String</code> with the associated ID or <code>null</code> if the name does * not exist. */ protected String getProgrammerConfigId(String name) { for (String id : fProgCfgIDs.keySet()) { String cfgname = fProgCfgIDs.get(id); if (cfgname.equals(name)) { return id; } } // name not found return null; } /** * Get the name of the ProgrammerConfig for the given ID. * * @param id * <code>String</code> with the ID * @return <code>String</code> with the name or <code>null</code> if the ID does not exist. */ protected String getProgrammerConfigName(String id) { return fProgCfgIDs.get(id); } /** * Get the {@link ProgrammerConfig} with the given ID. * <p> * This method will first check if a config with the ID is already in the new&modified * config list. If not, the call is passed on to the config manager. * </p> * * @see ProgrammerConfigManager#getConfig(String) * * @param configid * <code>String</code> with an ID value * @return The requested <code>ProgrammerConfig</code> or <code>null</code> if no config * with the given ID exists. */ protected ProgrammerConfig getProgrammerConfig(String configid) { if (fModifiedProgCfgs.containsKey(configid)) { // requested config is in the list of modified configs return fModifiedProgCfgs.get(configid); } // load the config from the preference store return fCfgManager.getConfig(configid); } /** * Reload the list of all ProgrammerConfigs from the preference store. * <p> * This will clear any added / modified configs, so only call this to init the GUI or to restore * the defaults. * </p> * <p> * Interested extending classes are informed about the new list via the * {@link #doProgConfigsChanged(String[], int)} hook method. * </p> */ protected void loadProgrammerConfigs() { // Clear the list of previously modified ProgrammerConfigs fModifiedProgCfgs.clear(); // Now read the list of configs from the preferences, then // create a List of all names, // sort them and finally // inform any extending classes about the new list fProgCfgIDs = fCfgManager.getAllConfigNames(); List<String> allCfgNames = new ArrayList<String>(fProgCfgIDs.size()); for (String cfgname : fProgCfgIDs.values()) { allCfgNames.add(cfgname); } Collections.sort(allCfgNames); // inform the interested superclasses about the new list. // The selection index is set at -1 to indicate that no entry in // particualar should be selected. doProgConfigsChanged(allCfgNames.toArray(new String[allCfgNames.size()]), -1); } /** * Add a new / modified {@link ProgrammerConfig} to the list of modified configs. * <p> * The given config is <strong>not</strong> saved to the preferences until the Apply or OK * buttons are clicked by the user * </p> * * @param newconfig */ protected void addProgrammerConfig(ProgrammerConfig config) { String configid = config.getId(); String configname = config.getName(); // Add / replace the config in the internal lists fModifiedProgCfgs.put(configid, config); fProgCfgIDs.put(configid, configname); // Now get the list of all config names and sort it, List<String> allnames = new ArrayList<String>(fProgCfgIDs.values()); Collections.sort(allnames); // find the name of the config in the list int newindex = allnames.indexOf(configname); // Inform any interested extending classes about the change doProgConfigsChanged(allnames.toArray(new String[fProgCfgIDs.size()]), newindex); return; } /** * List of ProgrammerConfigs has changed. * <p> * This is a hook for extending classes to be notified if the list of all available * ProgrammerConfigs has changed. * </p> * * @param configs * Array of <code>String</code> with the names of all available configs. * @param selectedindex * <code>int</code> with the index of the config that caused the list to be * reloaded. */ protected void doProgConfigsChanged(String[] configs, int selectedindex) { }; /** * Save all ProgrammerConfigs that have been added or edited on this Tab. * <p> * In case of Exceptions writing to the preferences, a status message is written to the system * log. * </p> */ protected void saveProgrammerConfigs() { // Go thru all modified configs and save them. // Afterwards the list of modified configs is cleared. for (ProgrammerConfig cfg : fModifiedProgCfgs.values()) { try { fCfgManager.saveConfig(cfg); } catch (BackingStoreException e) { // Inform the user that the save failed. IStatus status = new Status(Status.ERROR, AVRPlugin.PLUGIN_ID, "Can't save Programmer Configuration [" + cfg.getName() + "] to the preference storage area", e); AVRPlugin.getDefault().log(status); ErrorDialog.openError(super.usercomp.getShell(), "AVR Properties Error", null, status); } } fModifiedProgCfgs.clear(); } /** * Check if the given ProgrammerConfig ID is valid, i.e. exists. * <p> * This method checks the internal list of modified configs first, and if no config with the ID * is in this list, pass the question onto the <code>ProgrammerConfigManager</code>. * </p> * * @see ProgrammerConfigManager#isValidId(String) * * @param id * The ID value * @return <code>true</code> if the id exists, <code>false</code> otherwise. */ protected boolean isValidId(String id) { // Check the list of modified configs if (fModifiedProgCfgs.containsKey(id)) { return true; } // else check what the config manager knows return fCfgManager.isValidId(id); } /** * Update the avrdude command line preview. * <p> * This is a convenience method equivalent to * * <pre> * ((PageAVRDude) page).updatePreview(props); * </pre> * * </p> * * @param props * The <code>AVRProjectProperties</code> for which to display the preview */ protected void updateAVRDudePreview(AVRDudeProperties props) { if (page instanceof PageAVRDude) { PageAVRDude avrdudepage = (PageAVRDude) page; avrdudepage.updatePreview(props); } } }