001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.editor.product;
011:
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.Iterator;
015: import java.util.TreeMap;
016:
017: import org.eclipse.core.resources.IFile;
018: import org.eclipse.core.resources.IProject;
019: import org.eclipse.core.runtime.CoreException;
020: import org.eclipse.core.runtime.IAdaptable;
021: import org.eclipse.core.runtime.QualifiedName;
022: import org.eclipse.jdt.core.IJavaProject;
023: import org.eclipse.jface.action.Action;
024: import org.eclipse.jface.action.IMenuManager;
025: import org.eclipse.jface.action.Separator;
026: import org.eclipse.jface.viewers.ISelection;
027: import org.eclipse.jface.viewers.IStructuredSelection;
028: import org.eclipse.jface.viewers.StructuredSelection;
029: import org.eclipse.jface.viewers.TableViewer;
030: import org.eclipse.jface.viewers.Viewer;
031: import org.eclipse.jface.viewers.ViewerComparator;
032: import org.eclipse.jface.window.Window;
033: import org.eclipse.jface.wizard.WizardDialog;
034: import org.eclipse.osgi.service.resolver.BundleDescription;
035: import org.eclipse.osgi.service.resolver.HostSpecification;
036: import org.eclipse.pde.core.IModelChangedEvent;
037: import org.eclipse.pde.core.plugin.IPluginBase;
038: import org.eclipse.pde.core.plugin.IPluginModelBase;
039: import org.eclipse.pde.core.plugin.PluginRegistry;
040: import org.eclipse.pde.internal.core.IPluginModelListener;
041: import org.eclipse.pde.internal.core.PluginModelDelta;
042: import org.eclipse.pde.internal.core.TargetPlatformHelper;
043: import org.eclipse.pde.internal.core.iproduct.IProduct;
044: import org.eclipse.pde.internal.core.iproduct.IProductModel;
045: import org.eclipse.pde.internal.core.iproduct.IProductModelFactory;
046: import org.eclipse.pde.internal.core.iproduct.IProductPlugin;
047: import org.eclipse.pde.internal.ui.IPDEUIConstants;
048: import org.eclipse.pde.internal.ui.PDEPlugin;
049: import org.eclipse.pde.internal.ui.PDEUIMessages;
050: import org.eclipse.pde.internal.ui.editor.FormLayoutFactory;
051: import org.eclipse.pde.internal.ui.editor.PDEFormPage;
052: import org.eclipse.pde.internal.ui.editor.TableSection;
053: import org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor;
054: import org.eclipse.pde.internal.ui.elements.DefaultTableProvider;
055: import org.eclipse.pde.internal.ui.parts.TablePart;
056: import org.eclipse.pde.internal.ui.search.dependencies.DependencyCalculator;
057: import org.eclipse.pde.internal.ui.util.PersistablePluginObject;
058: import org.eclipse.pde.internal.ui.util.SWTUtil;
059: import org.eclipse.pde.internal.ui.wizards.plugin.NewFragmentProjectWizard;
060: import org.eclipse.pde.internal.ui.wizards.plugin.NewPluginProjectWizard;
061: import org.eclipse.swt.SWT;
062: import org.eclipse.swt.events.SelectionAdapter;
063: import org.eclipse.swt.events.SelectionEvent;
064: import org.eclipse.swt.layout.GridData;
065: import org.eclipse.swt.widgets.Button;
066: import org.eclipse.swt.widgets.Composite;
067: import org.eclipse.swt.widgets.Control;
068: import org.eclipse.swt.widgets.Table;
069: import org.eclipse.ui.IEditorInput;
070: import org.eclipse.ui.IFileEditorInput;
071: import org.eclipse.ui.IWorkingSet;
072: import org.eclipse.ui.IWorkingSetManager;
073: import org.eclipse.ui.PlatformUI;
074: import org.eclipse.ui.actions.ActionFactory;
075: import org.eclipse.ui.dialogs.ElementListSelectionDialog;
076: import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
077: import org.eclipse.ui.forms.widgets.FormToolkit;
078: import org.eclipse.ui.forms.widgets.Section;
079:
080: public class PluginSection extends TableSection implements
081: IPluginModelListener {
082:
083: class ContentProvider extends DefaultTableProvider {
084: public Object[] getElements(Object parent) {
085: return getProduct().getPlugins();
086: }
087: }
088:
089: private TableViewer fPluginTable;
090: private Button fIncludeOptionalButton;
091: public static final QualifiedName OPTIONAL_PROPERTY = new QualifiedName(
092: IPDEUIConstants.PLUGIN_ID, "product.includeOptional"); //$NON-NLS-1$
093:
094: public PluginSection(PDEFormPage formPage, Composite parent) {
095: super (formPage, parent, Section.DESCRIPTION, getButtonLabels());
096: }
097:
098: private static String[] getButtonLabels() {
099: String[] labels = new String[9];
100: labels[0] = PDEUIMessages.Product_PluginSection_add;
101: labels[1] = PDEUIMessages.Product_PluginSection_working;
102: labels[2] = PDEUIMessages.Product_PluginSection_required;
103: labels[3] = PDEUIMessages.PluginSection_remove;
104: labels[4] = PDEUIMessages.Product_PluginSection_removeAll;
105: labels[5] = null;
106: labels[6] = null;
107: labels[7] = PDEUIMessages.Product_PluginSection_newPlugin;
108: labels[8] = PDEUIMessages.Product_PluginSection_newFragment;
109: return labels;
110: }
111:
112: /* (non-Javadoc)
113: * @see org.eclipse.pde.internal.ui.editor.PDESection#createClient(org.eclipse.ui.forms.widgets.Section, org.eclipse.ui.forms.widgets.FormToolkit)
114: */
115: protected void createClient(Section section, FormToolkit toolkit) {
116:
117: section.setLayout(FormLayoutFactory.createClearGridLayout(
118: false, 1));
119: GridData sectionData = new GridData(GridData.FILL_BOTH);
120: sectionData.verticalSpan = 2;
121: section.setLayoutData(sectionData);
122:
123: Composite container = createClientContainer(section, 2, toolkit);
124: createViewerPartControl(container, SWT.MULTI, 2, toolkit);
125: container.setLayoutData(new GridData(GridData.FILL_BOTH));
126:
127: createOptionalDependenciesButton(container);
128:
129: TablePart tablePart = getTablePart();
130: fPluginTable = tablePart.getTableViewer();
131: fPluginTable.setContentProvider(new ContentProvider());
132: fPluginTable.setLabelProvider(PDEPlugin.getDefault()
133: .getLabelProvider());
134: fPluginTable.setComparator(new ViewerComparator() {
135: public int compare(Viewer viewer, Object e1, Object e2) {
136: IProductPlugin p1 = (IProductPlugin) e1;
137: IProductPlugin p2 = (IProductPlugin) e2;
138: return super .compare(viewer, p1.getId(), p2.getId());
139: }
140: });
141: GridData data = (GridData) tablePart.getControl()
142: .getLayoutData();
143: data.minimumWidth = 200;
144: fPluginTable.setInput(getProduct());
145:
146: tablePart.setButtonEnabled(0, isEditable());
147: tablePart.setButtonEnabled(1, isEditable());
148: tablePart.setButtonEnabled(2, isEditable());
149:
150: // remove buttons will be updated on refresh
151:
152: tablePart.setButtonEnabled(7, isEditable());
153: tablePart.setButtonEnabled(8, isEditable());
154:
155: toolkit.paintBordersFor(container);
156: section.setClient(container);
157:
158: section.setText(PDEUIMessages.Product_PluginSection_title);
159: section
160: .setDescription(PDEUIMessages.Product_PluginSection_desc);
161: getModel().addModelChangedListener(this );
162: }
163:
164: private void createOptionalDependenciesButton(Composite container) {
165: if (isEditable()) {
166: fIncludeOptionalButton = new Button(container, SWT.CHECK);
167: fIncludeOptionalButton
168: .setText(PDEUIMessages.PluginSection_includeOptional);
169: // initialize value
170: IEditorInput input = getPage().getEditorInput();
171: if (input instanceof IFileEditorInput) {
172: IFile file = ((IFileEditorInput) input).getFile();
173: try {
174: fIncludeOptionalButton
175: .setSelection("true".equals(file.getPersistentProperty(OPTIONAL_PROPERTY))); //$NON-NLS-1$
176: } catch (CoreException e) {
177: }
178: }
179: // create listener to save value when the checkbox is changed
180: fIncludeOptionalButton
181: .addSelectionListener(new SelectionAdapter() {
182: public void widgetSelected(SelectionEvent e) {
183: IEditorInput input = getPage()
184: .getEditorInput();
185: if (input instanceof IFileEditorInput) {
186: IFile file = ((IFileEditorInput) input)
187: .getFile();
188: try {
189: file
190: .setPersistentProperty(
191: OPTIONAL_PROPERTY,
192: fIncludeOptionalButton
193: .getSelection() ? "true" : null); //$NON-NLS-1$
194: } catch (CoreException e1) {
195: }
196: }
197: }
198: });
199: }
200: }
201:
202: /* (non-Javadoc)
203: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#buttonSelected(int)
204: */
205: protected void buttonSelected(int index) {
206: switch (index) {
207: case 0:
208: handleAdd();
209: break;
210: case 1:
211: handleAddWorkingSet();
212: break;
213: case 2:
214: handleAddRequired(getProduct().getPlugins(),
215: fIncludeOptionalButton.getSelection());
216: break;
217: case 3:
218: handleDelete();
219: break;
220: case 4:
221: handleRemoveAll();
222: break;
223: case 7:
224: handleNewPlugin();
225: break;
226: case 8:
227: handleNewFragment();
228: }
229: }
230:
231: private void handleNewFragment() {
232: NewFragmentProjectWizard wizard = new NewFragmentProjectWizard();
233: WizardDialog dialog = new WizardDialog(PDEPlugin
234: .getActiveWorkbenchShell(), wizard);
235: dialog.create();
236: SWTUtil.setDialogSize(dialog, 400, 500);
237: if (dialog.open() == Window.OK) {
238: addPlugin(wizard.getFragmentId());
239: }
240: }
241:
242: private void handleNewPlugin() {
243: NewPluginProjectWizard wizard = new NewPluginProjectWizard();
244: WizardDialog dialog = new WizardDialog(PDEPlugin
245: .getActiveWorkbenchShell(), wizard);
246: dialog.create();
247: SWTUtil.setDialogSize(dialog, 400, 500);
248: if (dialog.open() == Window.OK) {
249: addPlugin(wizard.getPluginId());
250: }
251: }
252:
253: /* (non-Javadoc)
254: * @see org.eclipse.pde.internal.ui.editor.TableSection#handleDoubleClick(org.eclipse.jface.viewers.IStructuredSelection)
255: */
256: protected void handleDoubleClick(IStructuredSelection selection) {
257: handleOpen(selection);
258: }
259:
260: /* (non-Javadoc)
261: * @see org.eclipse.ui.forms.AbstractFormPart#dispose()
262: */
263: public void dispose() {
264: IProductModel model = getModel();
265: if (model != null)
266: model.removeModelChangedListener(this );
267: super .dispose();
268: }
269:
270: /* (non-Javadoc)
271: * @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String)
272: */
273: public boolean doGlobalAction(String actionId) {
274: if (actionId.equals(ActionFactory.DELETE.getId())) {
275: handleDelete();
276: return true;
277: }
278: if (actionId.equals(ActionFactory.CUT.getId())) {
279: handleDelete();
280: return false;
281: }
282: if (actionId.equals(ActionFactory.PASTE.getId())) {
283: doPaste();
284: return true;
285: }
286: return false;
287: }
288:
289: protected boolean canPaste(Object target, Object[] objects) {
290: for (int i = 0; i < objects.length; i++) {
291: if (objects[i] instanceof IProductPlugin)
292: return true;
293: }
294: return false;
295: }
296:
297: /* (non-Javadoc)
298: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#fillContextMenu(org.eclipse.jface.action.IMenuManager)
299: */
300: protected void fillContextMenu(IMenuManager manager) {
301: IStructuredSelection ssel = (IStructuredSelection) fPluginTable
302: .getSelection();
303: if (ssel == null)
304: return;
305:
306: Action openAction = new Action(PDEUIMessages.PluginSection_open) {
307: public void run() {
308: handleDoubleClick((IStructuredSelection) fPluginTable
309: .getSelection());
310: }
311: };
312: openAction.setEnabled(isEditable() && ssel.size() == 1);
313: manager.add(openAction);
314:
315: manager.add(new Separator());
316:
317: Action removeAction = new Action(
318: PDEUIMessages.PluginSection_remove) {
319: public void run() {
320: handleDelete();
321: }
322: };
323: removeAction.setEnabled(isEditable() && ssel.size() > 0);
324: manager.add(removeAction);
325:
326: Action removeAll = new Action(
327: PDEUIMessages.PluginSection_removeAll) {
328: public void run() {
329: handleRemoveAll();
330: }
331: };
332: removeAll.setEnabled(isEditable());
333: manager.add(removeAll);
334:
335: manager.add(new Separator());
336:
337: getPage().getPDEEditor().getContributor()
338: .contextMenuAboutToShow(manager);
339: }
340:
341: private void handleOpen(IStructuredSelection selection) {
342: Object object = selection.getFirstElement();
343: if (object instanceof IProductPlugin) {
344: ManifestEditor.openPluginEditor(((IProductPlugin) object)
345: .getId());
346: }
347: }
348:
349: public static void handleAddRequired(IProductPlugin[] plugins,
350: boolean includeOptional) {
351: if (plugins.length == 0)
352: return;
353:
354: ArrayList list = new ArrayList(plugins.length);
355: for (int i = 0; i < plugins.length; i++) {
356: list.add(TargetPlatformHelper.getState().getBundle(
357: plugins[i].getId(), null));
358: }
359: DependencyCalculator calculator = new DependencyCalculator(
360: includeOptional);
361: calculator.findDependencies(list.toArray());
362:
363: BundleDescription[] bundles = TargetPlatformHelper.getState()
364: .getBundles();
365: for (int i = 0; i < bundles.length; i++) {
366: HostSpecification host = bundles[i].getHost();
367: if (host != null
368: && !("org.eclipse.ui.workbench.compatibility".equals(bundles[i].getSymbolicName())) //$NON-NLS-1$
369: && calculator.containsPluginId(host.getName())) { //$NON-NLS-1$
370: calculator.findDependency(bundles[i]);
371: }
372: }
373:
374: Collection dependencies = calculator.getBundleIDs();
375:
376: IProduct product = plugins[0].getProduct();
377: IProductModelFactory factory = product.getModel().getFactory();
378: IProductPlugin[] requiredPlugins = new IProductPlugin[dependencies
379: .size()];
380: int i = 0;
381: Iterator iter = dependencies.iterator();
382: while (iter.hasNext()) {
383: String id = iter.next().toString();
384: IProductPlugin plugin = factory.createPlugin();
385: plugin.setId(id);
386: requiredPlugins[i++] = plugin;
387: }
388: product.addPlugins(requiredPlugins);
389: }
390:
391: private void handleAddWorkingSet() {
392: IWorkingSetManager manager = PlatformUI.getWorkbench()
393: .getWorkingSetManager();
394: IWorkingSetSelectionDialog dialog = manager
395: .createWorkingSetSelectionDialog(PDEPlugin
396: .getActiveWorkbenchShell(), true);
397: if (dialog.open() == Window.OK) {
398: IWorkingSet[] workingSets = dialog.getSelection();
399: IProduct product = getProduct();
400: IProductModelFactory factory = product.getModel()
401: .getFactory();
402: ArrayList pluginList = new ArrayList();
403: for (int i = 0; i < workingSets.length; i++) {
404: IAdaptable[] elements = workingSets[i].getElements();
405: for (int j = 0; j < elements.length; j++) {
406: IPluginModelBase model = findModel(elements[j]);
407: if (model != null) {
408: IProductPlugin plugin = factory.createPlugin();
409: IPluginBase base = model.getPluginBase();
410: plugin.setId(base.getId());
411: pluginList.add(plugin);
412: }
413: }
414: }
415: product.addPlugins((IProductPlugin[]) pluginList
416: .toArray(new IProductPlugin[pluginList.size()]));
417: }
418: }
419:
420: private void handleRemoveAll() {
421: IProduct product = getProduct();
422: product.removePlugins(product.getPlugins());
423: }
424:
425: private void handleDelete() {
426: IStructuredSelection ssel = (IStructuredSelection) fPluginTable
427: .getSelection();
428: if (ssel.size() > 0) {
429: Object[] objects = ssel.toArray();
430: IProductPlugin[] plugins = new IProductPlugin[objects.length];
431: System.arraycopy(objects, 0, plugins, 0, objects.length);
432: getProduct().removePlugins(plugins);
433: }
434: }
435:
436: private void handleAdd() {
437: ElementListSelectionDialog dialog = new ElementListSelectionDialog(
438: PDEPlugin.getActiveWorkbenchShell(), PDEPlugin
439: .getDefault().getLabelProvider());
440: dialog.setElements(getBundles());
441: dialog.setTitle(PDEUIMessages.PluginSelectionDialog_title);
442: dialog.setMessage(PDEUIMessages.PluginSelectionDialog_message);
443: dialog.setMultipleSelection(true);
444: if (dialog.open() == Window.OK) {
445: Object[] bundles = dialog.getResult();
446: for (int i = 0; i < bundles.length; i++) {
447: addPlugin(((BundleDescription) bundles[i])
448: .getSymbolicName());
449: }
450: }
451: }
452:
453: private BundleDescription[] getBundles() {
454: TreeMap map = new TreeMap();
455: IProduct product = getProduct();
456: BundleDescription[] bundles = TargetPlatformHelper.getState()
457: .getBundles();
458: for (int i = 0; i < bundles.length; i++) {
459: String id = bundles[i].getSymbolicName();
460: if (!product.containsPlugin(id)) {
461: map.put(id, bundles[i]);
462: }
463: }
464: return (BundleDescription[]) map.values().toArray(
465: new BundleDescription[map.size()]);
466: }
467:
468: private void addPlugin(String id) {
469: IProduct product = getProduct();
470: IProductModelFactory factory = product.getModel().getFactory();
471: IProductPlugin plugin = factory.createPlugin();
472: plugin.setId(id);
473: product.addPlugins(new IProductPlugin[] { plugin });
474: fPluginTable.setSelection(new StructuredSelection(plugin));
475: }
476:
477: private IProduct getProduct() {
478: return getModel().getProduct();
479: }
480:
481: private IProductModel getModel() {
482: return (IProductModel) getPage().getPDEEditor()
483: .getAggregateModel();
484: }
485:
486: /* (non-Javadoc)
487: * @see org.eclipse.pde.internal.ui.editor.PDESection#modelChanged(org.eclipse.pde.core.IModelChangedEvent)
488: */
489: public void modelChanged(IModelChangedEvent e) {
490: // No need to call super, handling world changed event here
491: if (e.getChangeType() == IModelChangedEvent.WORLD_CHANGED) {
492: handleModelEventWorldChanged(e);
493: return;
494: }
495: Object[] objects = e.getChangedObjects();
496: if (e.getChangeType() == IModelChangedEvent.INSERT) {
497: for (int i = 0; i < objects.length; i++) {
498: if (objects[i] instanceof IProductPlugin)
499: fPluginTable.add(objects[i]);
500: }
501: } else if (e.getChangeType() == IModelChangedEvent.REMOVE) {
502:
503: Table table = fPluginTable.getTable();
504: int index = table.getSelectionIndex();
505:
506: for (int i = 0; i < objects.length; i++) {
507: if (objects[i] instanceof IProductPlugin)
508: fPluginTable.remove(objects[i]);
509: }
510:
511: // Update Selection
512:
513: int count = table.getItemCount();
514:
515: if (count == 0) {
516: // Nothing to select
517: } else if (index < count) {
518: table.setSelection(index);
519: } else {
520: table.setSelection(count - 1);
521: }
522:
523: }
524: updateRemoveButtons(false, true);
525: }
526:
527: /**
528: * @param event
529: */
530: private void handleModelEventWorldChanged(IModelChangedEvent event) {
531: // This section can get disposed if the configuration is changed from
532: // plugins to features or vice versa. Subsequently, the configuration
533: // page is removed and readded. In this circumstance, abort the
534: // refresh
535: if (fPluginTable.getTable().isDisposed()) {
536: return;
537: }
538: // Reload the input
539: fPluginTable.setInput(getProduct());
540: // Perform the refresh
541: refresh();
542: }
543:
544: /* (non-Javadoc)
545: * @see org.eclipse.ui.forms.AbstractFormPart#refresh()
546: */
547: public void refresh() {
548: fPluginTable.refresh();
549: updateRemoveButtons(true, true);
550: super .refresh();
551: }
552:
553: /* (non-Javadoc)
554: * @see org.eclipse.pde.internal.core.IPluginModelListener#modelsChanged(org.eclipse.pde.internal.core.PluginModelDelta)
555: */
556: public void modelsChanged(PluginModelDelta delta) {
557: final Control control = fPluginTable.getControl();
558: if (!control.isDisposed()) {
559: control.getDisplay().asyncExec(new Runnable() {
560: public void run() {
561: if (!control.isDisposed()) {
562: fPluginTable.refresh();
563: updateRemoveButtons(true, true);
564: }
565: }
566: });
567: }
568: }
569:
570: private IPluginModelBase findModel(IAdaptable object) {
571: if (object instanceof IJavaProject)
572: object = ((IJavaProject) object).getProject();
573: if (object instanceof IProject)
574: return PluginRegistry.findModel((IProject) object);
575: if (object instanceof PersistablePluginObject) {
576: return PluginRegistry
577: .findModel(((PersistablePluginObject) object)
578: .getPluginID());
579: }
580: return null;
581: }
582:
583: protected void selectionChanged(IStructuredSelection selection) {
584: getPage().getPDEEditor().setSelection(selection);
585: updateRemoveButtons(true, false);
586: }
587:
588: public boolean setFormInput(Object input) {
589: if (input instanceof IProductPlugin) {
590: fPluginTable.setSelection(new StructuredSelection(input),
591: true);
592: return true;
593: }
594: return super .setFormInput(input);
595: }
596:
597: protected void doPaste(Object target, Object[] objects) {
598: IProductPlugin[] plugins;
599: if (objects instanceof IProductPlugin[])
600: plugins = (IProductPlugin[]) objects;
601: else {
602: plugins = new IProductPlugin[objects.length];
603: for (int i = 0; i < objects.length; i++)
604: if (objects[i] instanceof IProductPlugin)
605: plugins[i] = (IProductPlugin) objects[i];
606: }
607: getProduct().addPlugins(plugins);
608: }
609:
610: private void updateRemoveButtons(boolean updateRemove,
611: boolean updateRemoveAll) {
612: TablePart tablePart = getTablePart();
613: if (updateRemove) {
614: ISelection selection = getViewerSelection();
615: tablePart
616: .setButtonEnabled(
617: 3,
618: isEditable()
619: && !selection.isEmpty()
620: && selection instanceof IStructuredSelection
621: && ((IStructuredSelection) selection)
622: .getFirstElement() instanceof IProductPlugin);
623: }
624: int count = fPluginTable.getTable().getItemCount();
625: if (updateRemoveAll)
626: tablePart.setButtonEnabled(4, isEditable() && count > 0);
627: tablePart.setButtonEnabled(2, isEditable() && count > 0);
628: }
629:
630: protected boolean createCount() {
631: return true;
632: }
633:
634: public boolean includeOptionalDependencies() {
635: return fIncludeOptionalButton.getSelection();
636: }
637: }
|