/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.ui.io; import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.dialogs.DialogPage; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import de.fhg.igd.eclipse.util.extension.ExtensionObjectFactoryCollection; import de.fhg.igd.eclipse.util.extension.FactoryFilter; import eu.esdihumboldt.hale.common.core.io.IOProvider; import eu.esdihumboldt.hale.common.core.io.ImportProvider; import eu.esdihumboldt.hale.common.core.io.extension.IOProviderDescriptor; import eu.esdihumboldt.hale.ui.HaleWizardPage; import eu.esdihumboldt.hale.ui.io.ImportSource.SourceConfiguration; import eu.esdihumboldt.hale.ui.io.internal.WizardPageDecorator; import eu.esdihumboldt.hale.ui.io.source.internal.ImportSourceExtension; import eu.esdihumboldt.hale.ui.io.source.internal.ImportSourceFactory; /** * Wizard page that allows selecting a source file or provider. * * @param <W> the concrete I/O wizard type * @param <P> the {@link IOProvider} type used in the wizard * * @author Simon Templer * @partner 01 / Fraunhofer Institute for Computer Graphics Research * @since 2.5 */ public class ImportSelectSourcePage<P extends ImportProvider, W extends ImportWizard<P>> extends IOWizardPage<P, W> { /** * Import source page */ public class SourcePage extends WizardPageDecorator implements SourceConfiguration<P> { private final ImportSource<P> importSource; private final int index; private IOProviderDescriptor factory; private IContentType contentType; private String message; private boolean complete = false; private int messageType = DialogPage.NONE; private String errorMessage; /** * Create an import source page and add it to the {@link #sources} list. * * @param importSource the corresponding import source * @param parent the parent composite * @param initialContentType the content type the import source page * should be initialized with, may be <code>null</code> */ public SourcePage(ImportSource<P> importSource, Composite parent, IContentType initialContentType) { super(ImportSelectSourcePage.this); this.importSource = importSource; sources.add(this); index = sources.size() - 1; setContentType(initialContentType); importSource.setPage(this); importSource.setConfiguration(this); importSource.createControls(parent); } /** * @see WizardPageDecorator#getWizard() */ @Override public W getWizard() { return ImportSelectSourcePage.this.getWizard(); } /** * Activate the source page. This will apply the stored content type, * provider factory, messages and page completeness. */ public void activate() { getWizard().setContentType(contentType); getWizard().setProviderFactory(factory); super.setMessage(message, messageType); super.setErrorMessage(errorMessage); super.setPageComplete(complete); importSource.onActivate(); } private boolean isActive() { synchronized (ImportSelectSourcePage.this) { return index == activeIndex; } } /** * @see SourceConfiguration#getFactories() */ @Override public Collection<IOProviderDescriptor> getFactories() { return getWizard().getFactories(); } /** * @see SourceConfiguration#setProviderFactory(IOProviderDescriptor) */ @Override public void setProviderFactory(IOProviderDescriptor factory) { this.factory = factory; if (isActive()) { getWizard().setProviderFactory(factory); } } /** * @see ImportSource.SourceConfiguration#getProviderFactory() */ @Override public IOProviderDescriptor getProviderFactory() { return factory; } /** * @see ImportSource.SourceConfiguration#setContentType(IContentType) */ @Override public void setContentType(IContentType contentType) { this.contentType = contentType; if (isActive()) { getWizard().setContentType(contentType); } } /** * @see WizardPageDecorator#getErrorMessage() */ @Override public String getErrorMessage() { return errorMessage; } /** * @see WizardPageDecorator#isPageComplete() */ @Override public boolean isPageComplete() { return complete; } /** * @see WizardPageDecorator#getMessage() */ @Override public String getMessage() { return message; } /** * @see WizardPageDecorator#getMessageType() */ @Override public int getMessageType() { return messageType; } /** * @see WizardPageDecorator#setErrorMessage(String) */ @Override public void setErrorMessage(String newMessage) { this.errorMessage = newMessage; if (isActive()) { super.setErrorMessage(newMessage); } } /** * @see WizardPageDecorator#setMessage(String, int) */ @Override public void setMessage(String newMessage, int newType) { this.message = newMessage; this.messageType = newType; if (isActive()) { super.setMessage(newMessage, newType); } } /** * @see WizardPageDecorator#setPageComplete(boolean) */ @Override public void setPageComplete(boolean complete) { this.complete = complete; if (isActive()) { super.setPageComplete(complete); } } /** * @see WizardPageDecorator#setMessage(String) */ @Override public void setMessage(String newMessage) { this.message = newMessage; if (isActive()) { super.setMessage(newMessage); } } /** * @see SourceConfiguration#getContentType() */ @Override public IContentType getContentType() { return contentType; } /** * @return the importSource */ public ImportSource<P> getImportSource() { return importSource; } /** * @return the index */ public int getIndex() { return index; } /** * @see WizardPageDecorator#dispose() */ @Override public void dispose() { importSource.dispose(); // dispose the import source } } private final List<SourcePage> sources = new ArrayList<SourcePage>(); private int activeIndex = 0; private final Set<Image> images = new HashSet<Image>(); /** * Default constructor */ public ImportSelectSourcePage() { super("import.selSource"); setTitle("Import location"); setDescription("Please select a source for the import"); } /** * @see HaleWizardPage#createContent(Composite) */ @Override protected void createContent(Composite page) { // set content types for file field List<IOProviderDescriptor> factories = getWizard().getFactories(); final Set<IContentType> supportedTypes = new HashSet<IContentType>(); for (IOProviderDescriptor factory : factories) { supportedTypes.addAll(factory.getSupportedTypes()); } // get compatible sources List<ImportSourceFactory> availableSources = ImportSourceExtension.getInstance() .getFactories(new FactoryFilter<ImportSource<?>, ImportSourceFactory>() { @Override public boolean acceptFactory(ImportSourceFactory factory) { // check provider factory compatibility boolean providerMatch = factory.getProviderType().isAssignableFrom( getWizard().getProviderType()); if (!providerMatch) { return false; } // check content type compatibility IContentType ct = factory.getContentType(); if (ct == null) { return true; // any content type supported } else { // stated type must be present return supportedTypes.contains(ct); } } @Override public boolean acceptCollection( ExtensionObjectFactoryCollection<ImportSource<?>, ImportSourceFactory> collection) { return false; } }); if (availableSources == null || availableSources.isEmpty()) { Label label = new Label(page, SWT.NONE); label.setText("No import source available."); } else if (availableSources.size() == 1) { // add source directly createSource(availableSources.iterator().next(), page, supportedTypes); setActiveSource(0); } else { // add tab for each source page.setLayout(new FillLayout()); final TabFolder tabs = new TabFolder(page, SWT.NONE); for (ImportSourceFactory sourceFactory : availableSources) { TabItem item = new TabItem(tabs, SWT.NONE); item.setText(MessageFormat.format("From {0}", sourceFactory.getDisplayName())); // image URL iconURL = sourceFactory.getIconURL(); if (iconURL != null) { Image image = ImageDescriptor.createFromURL(iconURL).createImage(); if (image != null) { images.add(image); // remember for disposal item.setImage(image); } } // tooltip item.setToolTipText(sourceFactory.getDescription()); // content Composite wrapper = new Composite(tabs, SWT.NONE); wrapper.setLayout(GridLayoutFactory.swtDefaults().create()); // for // minimum // margin Composite content = new Composite(wrapper, SWT.NONE); content.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create()); createSource(sourceFactory, content, supportedTypes); item.setControl(wrapper); } tabs.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setActiveSource(tabs.getSelectionIndex()); } }); setActiveSource(0); } } /** * Set the active source. * * @param selectionIndex the index of the source to be activated */ private void setActiveSource(int selectionIndex) { synchronized (this) { activeIndex = selectionIndex; getActiveSource().activate(); } } /** * Get the active source or <code>null</code>. * * @return the active source */ private SourcePage getActiveSource() { synchronized (this) { if (activeIndex < sources.size()) { return sources.get(activeIndex); } } return null; } /** * Create an import source and add its controls to the given composite. * * @param sourceFactory the {@link ImportSource} factory * @param parent the parent composite, a custom layout may be assigned by * implementors * @param supportedTypes the set of supported content types */ @SuppressWarnings("unchecked") private void createSource(ImportSourceFactory sourceFactory, Composite parent, Set<IContentType> supportedTypes) { ImportSource<?> source; try { source = sourceFactory.createExtensionObject(); } catch (Exception e) { throw new RuntimeException(MessageFormat.format("Could not create import source {0}", sourceFactory.getIdentifier()), e); } // determine initial content type IContentType initialContentType = sourceFactory.getContentType(); assert supportedTypes.contains(initialContentType); ImportSource<P> compatibleSource = ((ImportSource<P>) source); // XXX // alternative // to // casting? // create the source page new SourcePage(compatibleSource, parent, initialContentType); } /** * @see IOWizardPage#updateConfiguration(IOProvider) */ @Override public boolean updateConfiguration(P provider) { SourcePage source = getActiveSource(); if (source != null) { return source.getImportSource().updateConfiguration(provider); } return false; } /** * @see HaleWizardPage#dispose() */ @Override public void dispose() { for (Image image : images) { image.dispose(); } for (SourcePage source : sources) { source.dispose(); } super.dispose(); } }