/******************************************************************************* * Copyright (c) 2008 * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed below, as Initial Contributors under such license. * The text of such license is available at * http://www.eclipse.org/legal/epl-v10.html. * * Contributors: * Henrik Lindberg *******************************************************************************/ package org.eclipse.equinox.p2.authoring; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.equinox.p2.authoring.forms.RichFormEditor; import org.eclipse.equinox.p2.authoring.internal.InstallableUnitBuilder; import org.eclipse.equinox.p2.authoring.internal.InstallableUnitEditorInput; import org.eclipse.equinox.p2.authoring.internal.ModelChangeEvent; import org.eclipse.equinox.p2.authoring.internal.P2AuthoringException; import org.eclipse.equinox.p2.authoring.internal.P2MetadataReader; import org.eclipse.equinox.p2.authoring.internal.SaveIURunnable; import org.eclipse.equinox.p2.authoring.internal.InstallableUnitBuilder.TouchpointTypeBuilder; import org.eclipse.equinox.p2.authoring.internal.touchpoints.UnknownTouchpoint; import org.eclipse.equinox.p2.authoring.spi.ITouchpointTypeDescriptor; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IPathEditorInput; import org.eclipse.ui.IURIEditorInput; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.editors.text.ILocationProvider; /** * A multi page Eclipse form based editor for p2 IU. * * The editor keeps track of two types of "dirty" state - a) the dirty state in the editor pages (and sub editors), * which reflect the dirty state in relation to the model object b) the model's dirty state. Editor pages are marked as * "clean" when the data in the editor has been "committed" to the model object. This happens frequently when the user * switches between pages in the editor, or when switching between details in a master detail setup. * * Changes to the model marks the model as "changed" (i.e. dirty), until the changed-state is cleared. The editor clears * this state when the model is saved to file. * * The Editor provides an event bus see {@link RichFormEditor#getEventBus()}. This event bus is also given to the model * object, and listeners interested in model change events can subscribe to these via the bus. The model emits * {@link ModelChangeEvent} event object instances. * * @author Henrik Lindberg * */ public class InstallableUnitEditor extends RichFormEditor { private static final String EXTENSION_FILTER = "*.iu"; //$NON-NLS-1$ private static final String TMP_SUFFIX = "iu"; //$NON-NLS-1$ private static final String TMP_PREFIX = "p2iu-"; //$NON-NLS-1$ private InstallableUnitBuilder m_iu; private boolean m_readOnly = false; private TouchpointTypeBuilder m_originalTouchpointType; private ITouchpointTypeDescriptor[] m_touchpointTypes; public InstallableUnitEditor() { setTmpPrefix(TMP_PREFIX); setTmpSuffix(TMP_SUFFIX); } @Override protected void addPages() { createActions(); try { addPage(new OverviewPage(this)); addPage(new RequiredCapabilitiesPage(this)); addPage(new ProvidedCapabilitiesPage(this)); addPage(new ArtifactsPage(this)); addPage(new InformationPage(this)); addPage(new TouchpointPage(this)); addPage(new UpdatePage(this)); } catch(PartInitException e) { // TODO: Proper logging e.printStackTrace(); } } public void doExternalSaveAs() { if(!commitChanges()) return; FileDialog dlg = new FileDialog(getSite().getShell(), SWT.SAVE); dlg.setFilterExtensions(new String[] { EXTENSION_FILTER }); final String location = dlg.open(); if(location == null) return; saveToPath(new Path(location)); } public InstallableUnitBuilder getInstallableUnit() { return m_iu; } @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { // super version sets the site, sets the input (without notify), and then installs a selection provider. // super.init(site, input); if(!(input instanceof ILocationProvider || input instanceof IPathEditorInput || // input instanceof IURIEditorInput || input instanceof InstallableUnitEditorInput)) throw new PartInitException("Invalid Input"); if(input instanceof IURIEditorInput) { try { input = getExternalFileEditorInput((IURIEditorInput)input); } catch(Exception e) { throw new PartInitException("Unable to open editor", e); } } InputStream stream = null; try { if(input instanceof InstallableUnitEditorInput) { m_readOnly = true; // make mutable copy m_iu = new InstallableUnitBuilder((((InstallableUnitEditorInput)input).getInstallableUnit())); } else { IPath path = (input instanceof ILocationProvider) ? ((ILocationProvider)input).getPath(input) : ((IPathEditorInput)input).getPath(); // Always allow edit of a file TODO: should perhaps check for extension = ".iu" m_readOnly = false; File file = path.toFile(); if(file.length() != 0) { stream = new FileInputStream(file); // note url passed is only for information - creates mutable copy for editing m_iu = new InstallableUnitBuilder(P2MetadataReader.readInstallableUnit(file.toURL(), stream, site .getActionBars().getStatusLineManager().getProgressMonitor())); } } // If we got a model object, set the event bus to use to send model change events. // if(m_iu != null) { m_iu.setEventBus(getEventBus()); m_originalTouchpointType = m_iu.getTouchpointType(); } setInputWithNotify(input); setPartName(input.getName() + (m_readOnly ? " (read only)" : "")); //$NON-NLS-1$ } catch(Exception e) { // TODO: Uses Buckminster exception wrapper throw new PartInitException(P2AuthoringException.wrap(e).getMessage()); } finally { try { stream.close(); } catch(IOException e) { } } } /** * Returns the original TouchpointType from the IU when read from the .iu file. This type is preserved as it may * represent an unknown type, and the user should be able to select this (i.e. keep it after changing to some other * type when editing). */ public TouchpointTypeBuilder getOriginalTouchpointType() { return m_originalTouchpointType; } /** * Overrides the default implementation by checking if the model object (the installable unit) is dirty. The default * implementation only checks if the editor pages are dirty, and they are marked as clean as soon as the model * object has been updated (comitted). */ @Override public boolean isDirty() { if(m_iu != null && m_iu.isChanged()) return true; return super.isDirty(); } public boolean isReadOnly() { return m_readOnly; } @Override public final void saveToPath(IPath path) { try { SaveIURunnable sr = new SaveIURunnable(m_iu.createInstallableUnit(), path); getSite().getWorkbenchWindow().run(true, true, sr); setInputWithNotify(sr.getSavedInput()); // mark the model object as unchanged m_iu.setChanged(false); setPartName(path.lastSegment()); firePropertyChange(IWorkbenchPart.PROP_TITLE); editorDirtyStateChanged(); } catch(InvocationTargetException e) { CoreException t = P2AuthoringException.wrap(e); String msg = "Unable to save file " + path; P2AuthoringUIPlugin.getDefault().getBundleLogger().error(t, msg); ErrorDialog.openError(getSite().getShell(), null, msg, t.getStatus()); } catch(InterruptedException e) { } } /** * Returns the available touchpoint type descriptors from the plugin plus an Unknown type descriptor with the * original typeId and version from the IU when read from file. * * @return */ public ITouchpointTypeDescriptor[] getTouchpointTypes() { if(m_touchpointTypes == null) { m_touchpointTypes = P2AuthoringUIPlugin.getDefault().getTouchpointTypes(); if(m_originalTouchpointType != null) { ITouchpointTypeDescriptor desc = P2AuthoringUIPlugin.getDefault().getTouchpointType( m_originalTouchpointType); if(desc == null) { ITouchpointTypeDescriptor[] result2 = new ITouchpointTypeDescriptor[m_touchpointTypes.length + 1]; System.arraycopy(m_touchpointTypes, 0, result2, 1, m_touchpointTypes.length); result2[0] = new UnknownTouchpoint(m_originalTouchpointType); m_touchpointTypes = result2; } } } return m_touchpointTypes; } /** * Returns the touchpoint type descriptor for the type. * * @param type * @return */ public ITouchpointTypeDescriptor getTouchpointType(TouchpointTypeBuilder type) { // null/none type, or a known type ITouchpointTypeDescriptor ttd = P2AuthoringUIPlugin.getDefault().getTouchpointType(type); // If not found, it must be the unknown type. if(ttd == null) return getTouchpointTypes()[0]; return ttd; } }