/******************************************************************************* * Copyright (c) 2010 Neil Bartlett. * 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: * Neil Bartlett - initial API and implementation *******************************************************************************/ package bndtools.editor.imports; import java.beans.PropertyChangeEvent; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.bndtools.utils.swt.SWTUtil; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.IMessageManager; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import aQute.bnd.build.model.BndEditModel; import aQute.bnd.build.model.clauses.ImportPattern; import aQute.bnd.header.Attrs; import aQute.bnd.osgi.Constants; import bndtools.editor.pkgpatterns.PkgPatternsListPart; import bndtools.utils.ModificationLock; public class ImportPatternsListPart extends PkgPatternsListPart<ImportPattern> { private class FixMissingStarsAction extends Action { public FixMissingStarsAction(String message) { super(message); } @Override public void run() { // Remove existing "*" patterns that are not in the last place List<ImportPattern> toRemove = new LinkedList<ImportPattern>(); for (Iterator<ImportPattern> iter = getClauses().iterator(); iter.hasNext();) { ImportPattern pattern = iter.next(); if (pattern.getName().equals("*") && iter.hasNext()) { toRemove.add(pattern); } } if (!toRemove.isEmpty()) { doRemoveClauses(toRemove); } // Add a "*" at the end, if not already present List<ImportPattern> patterns = getClauses(); if (patterns.size() != 0 && !patterns.get(patterns.size() - 1).getName().equals("*")) { ImportPattern starPattern = new ImportPattern("*", new Attrs()); ImportPatternsListPart.super.doAddClauses(Arrays.asList(starPattern), -1, false); } } } private final ModificationLock modifyLock = new ModificationLock(); private Text txtPattern; private Text txtVersion; private Button btnOptional; private Composite pnlDetails; public ImportPatternsListPart(Composite parent, FormToolkit toolkit, int style) { super(parent, toolkit, style, Constants.IMPORT_PACKAGE, "Customise Imports", new ImportPatternLabelProvider()); addPropertyChangeListener(PROP_SELECTION, this); } @Override protected void createSection(Section section, FormToolkit toolkit) { super.createSection(section, toolkit); Composite parentComposite = (Composite) getSection().getClient(); pnlDetails = toolkit.createComposite(parentComposite); toolkit.createLabel(pnlDetails, "Pattern:"); txtPattern = toolkit.createText(pnlDetails, ""); toolkit.createLabel(pnlDetails, "Version:"); txtVersion = toolkit.createText(pnlDetails, "", SWT.BORDER); btnOptional = toolkit.createButton(pnlDetails, "Optional", SWT.CHECK); pnlDetails.setLayout(new GridLayout(5, false)); txtPattern.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); txtVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); pnlDetails.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); SWTUtil.recurseEnable(false, pnlDetails); txtPattern.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { if (!modifyLock.isUnderModification()) { List<ImportPattern> selectedClauses = getSelection(); if (selectedClauses.size() == 1) { selectedClauses.get(0).setName(txtPattern.getText()); updateLabels(selectedClauses); validate(); markDirty(); } } } }); txtVersion.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { if (!modifyLock.isUnderModification()) { String text = txtVersion.getText(); if (text.length() == 0) text = null; List<ImportPattern> selectedClauses = getSelection(); for (ImportPattern clause : selectedClauses) { clause.getAttribs().put(Constants.VERSION_ATTRIBUTE, text); } updateLabels(selectedClauses); validate(); markDirty(); } } }); btnOptional.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (!modifyLock.isUnderModification()) { boolean optional = btnOptional.getSelection(); List<ImportPattern> patterns = getSelection(); for (ImportPattern pattern : patterns) { pattern.setOptional(optional); } updateLabels(patterns); validate(); markDirty(); } } }); } @Override protected void doAddClauses(Collection< ? extends ImportPattern> clauses, int index, boolean select) { boolean appendStar = getClauses().isEmpty(); super.doAddClauses(clauses, index, select); if (appendStar) { ImportPattern starPattern = new ImportPattern("*", new Attrs()); //$NON-NLS-1$ super.doAddClauses(Arrays.asList(starPattern), -1, false); } } @Override public void validate() { IMessageManager msgs = getManagedForm().getMessageManager(); msgs.setDecorationPosition(SWT.TOP | SWT.RIGHT); String noStarWarning = null; String actionMessage = null; List<ImportPattern> patterns = getClauses(); if (!patterns.isEmpty()) { for (Iterator<ImportPattern> iter = patterns.iterator(); iter.hasNext();) { ImportPattern pattern = iter.next(); if (pattern.getName().equals("*") && iter.hasNext()) { noStarWarning = "The catch-all pattern \"*\" should be in the last position."; actionMessage = "Move \"*\" pattern to the last position."; break; } } if (noStarWarning == null) { ImportPattern last = patterns.get(patterns.size() - 1); if (!last.getName().equals("*")) { noStarWarning = "The catch-all pattern \"*\" should be present and in the last position."; actionMessage = "Add missing \"*\" pattern."; } } } if (noStarWarning != null) { msgs.addMessage("_warning_no_star", noStarWarning, new FixMissingStarsAction(actionMessage), IMessageProvider.WARNING); } else { msgs.removeMessage("_warning_no_star"); } } @Override protected ImportPattern newHeaderClause(String text) { return new ImportPattern(text, new Attrs()); } @Override protected List<ImportPattern> loadFromModel(BndEditModel model) { return model.getImportPatterns(); } @Override protected void saveToModel(BndEditModel model, List< ? extends ImportPattern> clauses) { model.setImportPatterns(clauses); } @Override public void propertyChange(PropertyChangeEvent evt) { if (PROP_SELECTION.equals(evt.getPropertyName())) { final List<ImportPattern> selectedClauses = getSelection(); modifyLock.modifyOperation(new Runnable() { @Override public void run() { if (selectedClauses.isEmpty()) { SWTUtil.recurseEnable(false, pnlDetails); txtPattern.setText(""); txtVersion.setText(""); btnOptional.setSelection(false); } else if (selectedClauses.size() == 1) { SWTUtil.recurseEnable(true, pnlDetails); ImportPattern pattern = selectedClauses.get(0); txtPattern.setText(pattern.getName() != null ? pattern.getName() : ""); txtVersion.setText(pattern.getVersionRange() != null ? pattern.getVersionRange() : ""); btnOptional.setSelection(pattern.isOptional()); } else { SWTUtil.recurseEnable(false, pnlDetails); btnOptional.setEnabled(true); pnlDetails.setEnabled(true); boolean differs = false; boolean first = selectedClauses.get(0).isOptional(); for (ImportPattern pattern : selectedClauses) { if (first != pattern.isOptional()) { differs = true; break; } } if (differs) { btnOptional.setGrayed(true); } else { btnOptional.setGrayed(false); btnOptional.setSelection(first); } } } }); } else { super.propertyChange(evt); } } }