/******************************************************************************* * 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.editors; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.IFormPart; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.SectionPart; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import de.innot.avreclipse.core.toolinfo.fuses.ByteValueChangeEvent; import de.innot.avreclipse.core.toolinfo.fuses.ByteValues; import de.innot.avreclipse.core.toolinfo.fuses.IByteValuesChangeListener; /** * A <code>SectionPart</code> that can edit the comment field of a <code>ByteValues</code> * source object. * <p> * This class automatically creates a <code>Section</code> and adds it to the parent composite. * After the class has been instantiated it must be added to a <code>IManagedForm</code> to * participate in the lifecycle management of the managed form. * * <pre> * Composite parent = ... * FormToolkit toolkit = ... * IManagedForm managedForm = ... * * IFormPart part = new ByteValuesCommentPart(parent, toolkit, Section.TITLE_BAR); * managedForm.addPart(part); * </pre> * * </p> * <p> * This class implements the {@link IFormPart} interface to participate in the lifecycle management * of a managed form. To set the value of the BitField use * * <pre> * ByteValues bytevalues = ... * managedForm.setInput(bytevalues); * </pre> * * The <code>ByteValues</code> passed to the managedForm is the model for this * <code>SectionPart</code>. Unlike normal IFormParts all changes to the source ByteValues are * applied immediately, because other other editors might be affected by the change. Therefore this * class uses its own dirty / stale management and does not use the one provided by the superclass * {@link SectionPart} * </p> * <p> * This part also adds itself as a listener for changes to the ByteValues model. If the ByteValues * comment gets changed from outside, then this part is marked as stale. The new value will be set * during the refresh method. * </p> * * @author Thomas Holland * @since 2.3 * */ public class ByteValuesCommentPart extends SectionPart implements IByteValuesChangeListener { // // This stuff could be integrated into the ByteValuesMainPart class. // I have made it separate to // // 1. do not show this in the ByteValueEditor dialog for immediate fuse byte values, which // currently does not know anything about comments. // // 2. have more control in the layout of the FuseByteEditorPage class. // /** * The model for this <code>SectionPart</code>. Will only be written to in the * {@link #commit(boolean)} method. */ private ByteValues fByteValues; /** The text control of this section. */ private Text fText; /** Last clean comment value. Used to check if this part is currently dirty. */ private String fLastCleanComment; /** Current comment. Used to check if this part is currently stale. */ private String fCurrentComment; /** * Part is currently refreshing the value. Used to inhibit the ModifyTextListener. */ private boolean fInRefresh = false; /** * Create a new <code>SectionPart</code> to handle the comment of a <code>ByteValues</code> * object. * <p> * This constructor automatically creates a new section part inside the provided parent and * using the provided toolkit. * </p> * * @param parent * the parent * @param toolkit * the toolkit to use for the section * @param style * the section widget style */ public ByteValuesCommentPart(Composite parent, FormToolkit toolkit, int style) { super(parent, toolkit, style); getSection().setText("Notes"); } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#initialize(org.eclipse.ui.forms.IManagedForm) */ @Override public void initialize(IManagedForm form) { super.initialize(form); Section parent = getSection(); FormToolkit toolkit = form.getToolkit(); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.heightHint = 54; // TODO: make it 4 lines according to the used font. // Create the Section client area. Composite client = form.getToolkit().createComposite(parent); parent.setClient(client); client.setLayout(new GridLayout()); // And add the single Text control to it. fText = toolkit.createText(client, "", SWT.BORDER | SWT.MULTI); fText.setLayoutData(gd); fText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { if (fInRefresh) { // don't do anything if the new text value has been set in the refresh() method. return; } fCurrentComment = fText.getText(); fByteValues.setComment(fCurrentComment); // Our dirty state might have changed, depending on the new value. // Inform the parent ManagedForm - it will call our isDirty() implementation to get // the actual state. getManagedForm().dirtyStateChanged(); } }); } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#dispose() */ @Override public void dispose() { if (fByteValues != null) { fByteValues.removeChangeListener(this); } super.dispose(); } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#setFormInput(java.lang.Object) */ @Override public boolean setFormInput(Object input) { if (!(input instanceof ByteValues)) { return false; } fByteValues = (ByteValues) input; fByteValues.addChangeListener(this); refresh(); return true; } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#refresh() */ @Override public void refresh() { // refresh() was once called before setInput(), but I am not sure if this was a bug in the // Editor. I have left this test just in case, even if it is probably not required. if (fByteValues == null) { return; } String comment = fByteValues.getComment(); if (comment == null) { comment = ""; } fInRefresh = true; fText.setText(comment); fInRefresh = false; fLastCleanComment = fCurrentComment = comment; super.refresh(); } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#commit(boolean) */ @Override public void commit(boolean onSave) { fLastCleanComment = fCurrentComment = fByteValues.getComment(); super.commit(onSave); } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#isDirty() */ @Override public boolean isDirty() { // This part is dirty if the source ByteValues has a different value than what it had on the // last setInput(), refresh() or commit() String comment = fByteValues.getComment(); if (comment == null && fLastCleanComment == null) { return false; } if (comment == null && fLastCleanComment != null) { return true; } if (fByteValues.getComment().equals(fLastCleanComment)) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.ui.forms.AbstractFormPart#isStale() */ @Override public boolean isStale() { // This part is stale if the source ByteValues has a different value than what this part // thinks it should have. String comment = fByteValues.getComment(); if (comment == null && fCurrentComment == null) { return false; } if (comment == null && fCurrentComment != null) { return true; } if (fByteValues.getComment().equals(fCurrentComment)) { return false; } return true; } /* * (non-Javadoc) * * @see de.innot.avreclipse.core.toolinfo.fuses.IByteValuesChangeListener#byteValuesChanged(de.innot.avreclipse.core.toolinfo.fuses.ByteValueChangeEvent[]) */ public void byteValuesChanged(ByteValueChangeEvent[] events) { if (fInRefresh) { // don't listen to our own changes to the Comment return; } // go through all events and if any event changes the comment to a different value then mark // ourself as stale. for (ByteValueChangeEvent event : events) { if (event.name.equals(ByteValues.COMMENT_CHANGE_EVENT)) { // Our stale state might have changed, depending on the new value. // Inform the parent ManagedForm - it will call our isStale() implementation to get // the actual state. getManagedForm().staleStateChanged(); } } } }