001: /*******************************************************************************
002: * Copyright (c) 2000, 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.plugin;
011:
012: import java.io.ByteArrayInputStream;
013: import java.util.ArrayList;
014: import java.util.HashSet;
015: import java.util.Iterator;
016: import java.util.Vector;
017:
018: import org.eclipse.core.resources.IFile;
019: import org.eclipse.core.resources.IProject;
020: import org.eclipse.core.resources.IResource;
021: import org.eclipse.core.resources.ProjectScope;
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.NullProgressMonitor;
024: import org.eclipse.core.runtime.preferences.IEclipsePreferences;
025: import org.eclipse.jface.action.Action;
026: import org.eclipse.jface.action.IAction;
027: import org.eclipse.jface.action.IMenuManager;
028: import org.eclipse.jface.action.Separator;
029: import org.eclipse.jface.action.ToolBarManager;
030: import org.eclipse.jface.util.IPropertyChangeListener;
031: import org.eclipse.jface.util.PropertyChangeEvent;
032: import org.eclipse.jface.viewers.ISelection;
033: import org.eclipse.jface.viewers.IStructuredSelection;
034: import org.eclipse.jface.viewers.ITableLabelProvider;
035: import org.eclipse.jface.viewers.TableViewer;
036: import org.eclipse.jface.viewers.ViewerDropAdapter;
037: import org.eclipse.jface.window.Window;
038: import org.eclipse.pde.core.IBaseModel;
039: import org.eclipse.pde.core.IModelChangedEvent;
040: import org.eclipse.pde.core.IModelChangedListener;
041: import org.eclipse.pde.core.build.IBuild;
042: import org.eclipse.pde.core.build.IBuildEntry;
043: import org.eclipse.pde.core.build.IBuildModel;
044: import org.eclipse.pde.core.plugin.IPluginModel;
045: import org.eclipse.pde.core.plugin.IPluginModelBase;
046: import org.eclipse.pde.core.plugin.PluginRegistry;
047: import org.eclipse.pde.internal.core.ICoreConstants;
048: import org.eclipse.pde.internal.core.IPluginModelListener;
049: import org.eclipse.pde.internal.core.PDECore;
050: import org.eclipse.pde.internal.core.PluginModelDelta;
051: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModel;
052: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
053: import org.eclipse.pde.internal.core.plugin.ExternalPluginModel;
054: import org.eclipse.pde.internal.core.plugin.WorkspacePluginModel;
055: import org.eclipse.pde.internal.core.text.build.BuildEntry;
056: import org.eclipse.pde.internal.ui.PDEPlugin;
057: import org.eclipse.pde.internal.ui.PDEPluginImages;
058: import org.eclipse.pde.internal.ui.PDEUIMessages;
059: import org.eclipse.pde.internal.ui.editor.FormLayoutFactory;
060: import org.eclipse.pde.internal.ui.editor.PDEFormEditor;
061: import org.eclipse.pde.internal.ui.editor.PDEFormPage;
062: import org.eclipse.pde.internal.ui.editor.TableSection;
063: import org.eclipse.pde.internal.ui.editor.actions.SortAction;
064: import org.eclipse.pde.internal.ui.editor.build.BuildInputContext;
065: import org.eclipse.pde.internal.ui.editor.context.InputContext;
066: import org.eclipse.pde.internal.ui.elements.DefaultTableProvider;
067: import org.eclipse.pde.internal.ui.parts.TablePart;
068: import org.eclipse.pde.internal.ui.search.dependencies.AddNewDependenciesAction;
069: import org.eclipse.pde.internal.ui.util.SharedLabelProvider;
070: import org.eclipse.pde.internal.ui.wizards.PluginSelectionDialog;
071: import org.eclipse.swt.SWT;
072: import org.eclipse.swt.events.DisposeEvent;
073: import org.eclipse.swt.events.DisposeListener;
074: import org.eclipse.swt.events.SelectionAdapter;
075: import org.eclipse.swt.events.SelectionEvent;
076: import org.eclipse.swt.graphics.Cursor;
077: import org.eclipse.swt.graphics.Image;
078: import org.eclipse.swt.layout.GridData;
079: import org.eclipse.swt.layout.GridLayout;
080: import org.eclipse.swt.widgets.Button;
081: import org.eclipse.swt.widgets.Composite;
082: import org.eclipse.swt.widgets.Control;
083: import org.eclipse.swt.widgets.Display;
084: import org.eclipse.swt.widgets.Table;
085: import org.eclipse.swt.widgets.ToolBar;
086: import org.eclipse.ui.actions.ActionFactory;
087: import org.eclipse.ui.forms.events.HyperlinkAdapter;
088: import org.eclipse.ui.forms.events.HyperlinkEvent;
089: import org.eclipse.ui.forms.widgets.ExpandableComposite;
090: import org.eclipse.ui.forms.widgets.FormText;
091: import org.eclipse.ui.forms.widgets.FormToolkit;
092: import org.eclipse.ui.forms.widgets.Section;
093: import org.eclipse.ui.part.FileEditorInput;
094: import org.osgi.service.prefs.BackingStoreException;
095:
096: public class DependencyManagementSection extends TableSection implements
097: IModelChangedListener, IPluginModelListener,
098: IPropertyChangeListener {
099:
100: private TableViewer fAdditionalTable;
101: private Vector fAdditionalBundles;
102: private Action fNewAction;
103: private Action fRemoveAction;
104: private Action fOpenAction;
105: private Action fSortAction;
106: private Button fRequireBundleButton;
107: private Button fImportPackageButton;
108: private IProject fProject;
109:
110: private static final int ADD_INDEX = 0;
111: private static final int REMOVE_INDEX = 1;
112: private static final int UP_INDEX = 2;
113: private static final int DOWN_INDEX = 3;
114:
115: private static String ADD = PDEUIMessages.RequiresSection_add;
116: private static String REMOVE = PDEUIMessages.RequiresSection_delete;
117: private static String OPEN = PDEUIMessages.RequiresSection_open;
118: private static String UP = PDEUIMessages.RequiresSection_up;
119: private static String DOWN = PDEUIMessages.RequiresSection_down;
120:
121: class ContentProvider extends DefaultTableProvider {
122:
123: /* (non-Javadoc)
124: * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
125: */
126: public Object[] getElements(Object inputElement) {
127: if (fAdditionalBundles == null)
128: return createAdditionalBundles();
129: return fAdditionalBundles.toArray();
130: }
131:
132: private IBuildEntry getBuildInfo() {
133: IBuildEntry entry = null;
134: IBuildModel model = getBuildModel(false);
135: if (model == null)
136: return null;
137: IBuild buildObject = model.getBuild();
138: entry = buildObject
139: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
140: return entry;
141: }
142:
143: private Object[] createAdditionalBundles() {
144: IBuildEntry entry = getBuildInfo();
145: try {
146: if (entry != null) {
147: String[] tokens = entry.getTokens();
148: fAdditionalBundles = new Vector(tokens.length);
149: for (int i = 0; i < tokens.length; i++) {
150: fAdditionalBundles.add(tokens[i].trim());
151: }
152: return fAdditionalBundles.toArray();
153: }
154: return new Object[0];
155: } catch (Exception e) {
156: PDEPlugin.logException(e);
157: return new Object[0]; //If exception happen while getting bundles, return an empty table
158: }
159: }
160: }
161:
162: class SecondaryTableLabelProvider extends SharedLabelProvider
163: implements ITableLabelProvider {
164: public String getColumnText(Object obj, int index) {
165: return obj.toString();
166: }
167:
168: public Image getColumnImage(Object obj, int index) {
169: String pluginID = obj.toString();
170: IPluginModelBase model = PluginRegistry.findModel(pluginID);
171: if (model == null) {
172: return get(PDEPluginImages.DESC_REQ_PLUGIN_OBJ, F_ERROR);
173: } else if (model instanceof IBundlePluginModel
174: || model instanceof WorkspacePluginModel) {
175: return get(PDEPluginImages.DESC_REQ_PLUGIN_OBJ);
176: } else if (model instanceof ExternalPluginModel) {
177: return get(PDEPluginImages.DESC_PLUGIN_OBJ, F_EXTERNAL);
178: }
179: return null;
180: }
181: }
182:
183: public DependencyManagementSection(PDEFormPage formPage,
184: Composite parent) {
185: super (formPage, parent, ExpandableComposite.TWISTIE
186: | ExpandableComposite.COMPACT, new String[] { ADD,
187: REMOVE, UP, DOWN });
188: IBuildModel model = getBuildModel(false);
189: if (model != null) {
190: IBuildEntry entry = model.getBuild().getEntry(
191: IBuildEntry.SECONDARY_DEPENDENCIES);
192: if (entry != null && entry.getTokens().length > 0)
193: getSection().setExpanded(true);
194: }
195: }
196:
197: protected void createClient(Section section, FormToolkit toolkit) {
198: FormText text = toolkit.createFormText(section, true);
199: text.setText(PDEUIMessages.SecondaryBundlesSection_desc, false,
200: false);
201: section.setDescriptionControl(text);
202:
203: Composite container = createClientContainer(section, 2, toolkit);
204: createViewerPartControl(container, SWT.MULTI, 2, toolkit);
205: TablePart tablePart = getTablePart();
206: fAdditionalTable = tablePart.getTableViewer();
207:
208: fAdditionalTable.setContentProvider(new ContentProvider());
209: fAdditionalTable
210: .setLabelProvider(new SecondaryTableLabelProvider());
211: GridData gd = (GridData) fAdditionalTable.getTable()
212: .getLayoutData();
213: gd.heightHint = 150;
214: fAdditionalTable.getTable().setLayoutData(gd);
215:
216: gd = new GridData();
217: gd.horizontalSpan = 2;
218: FormText resolveText = toolkit.createFormText(container, true);
219: resolveText.setText(
220: PDEUIMessages.SecondaryBundlesSection_resolve, true,
221: true);
222: resolveText.setLayoutData(gd);
223: resolveText.addHyperlinkListener(new HyperlinkAdapter() {
224: public void linkActivated(HyperlinkEvent e) {
225: doAddDependencies();
226: }
227: });
228:
229: Composite comp = toolkit.createComposite(container);
230: comp.setLayout(new GridLayout(2, false));
231: gd = new GridData();
232: gd.horizontalSpan = 2;
233: comp.setLayoutData(gd);
234:
235: fRequireBundleButton = toolkit.createButton(comp,
236: "Require-Bundle", SWT.RADIO); //$NON-NLS-1$
237: gd = new GridData();
238: gd.horizontalIndent = 20;
239: fRequireBundleButton.setLayoutData(gd);
240: fRequireBundleButton
241: .addSelectionListener(new SelectionAdapter() {
242: public void widgetSelected(SelectionEvent e) {
243: savePreferences();
244: }
245: });
246:
247: fImportPackageButton = toolkit.createButton(comp,
248: "Import-Package", SWT.RADIO); //$NON-NLS-1$
249: gd = new GridData();
250: gd.horizontalIndent = 20;
251: fImportPackageButton.setLayoutData(gd);
252:
253: toolkit.paintBordersFor(container);
254: makeActions();
255: section.setClient(container);
256: section.setLayout(FormLayoutFactory.createClearGridLayout(
257: false, 1));
258: section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
259: section.setText(PDEUIMessages.SecondaryBundlesSection_title);
260: createSectionToolbar(section, toolkit);
261: initialize();
262: }
263:
264: private void createSectionToolbar(Section section,
265: FormToolkit toolkit) {
266: ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
267: ToolBar toolbar = toolBarManager.createControl(section);
268: final Cursor handCursor = new Cursor(Display.getCurrent(),
269: SWT.CURSOR_HAND);
270: toolbar.setCursor(handCursor);
271: // Cursor needs to be explicitly disposed
272: toolbar.addDisposeListener(new DisposeListener() {
273: public void widgetDisposed(DisposeEvent e) {
274: if ((handCursor != null)
275: && (handCursor.isDisposed() == false)) {
276: handCursor.dispose();
277: }
278: }
279: });
280:
281: // Add sort action to the tool bar
282: fSortAction = new SortAction(getTablePart().getTableViewer(),
283: PDEUIMessages.RequiresSection_sortAlpha, null, null,
284: this );
285: toolBarManager.add(fSortAction);
286:
287: toolBarManager.update(true);
288:
289: section.setTextClient(toolbar);
290: }
291:
292: private void savePreferences() {
293: if (fProject == null) {
294: IPluginModelBase model = (IPluginModelBase) getPage()
295: .getModel();
296: IResource resource = model.getUnderlyingResource();
297: if (resource == null)
298: return;
299: fProject = resource.getProject();
300: }
301: IEclipsePreferences pref = new ProjectScope(fProject)
302: .getNode(PDECore.PLUGIN_ID);
303:
304: if (fImportPackageButton.getSelection())
305: pref.putBoolean(ICoreConstants.RESOLVE_WITH_REQUIRE_BUNDLE,
306: false);
307: else
308: pref.remove(ICoreConstants.RESOLVE_WITH_REQUIRE_BUNDLE);
309: try {
310: pref.flush();
311: } catch (BackingStoreException e) {
312: PDEPlugin.logException(e);
313: }
314: }
315:
316: private void initialize() {
317: try {
318: IPluginModelBase model = (IPluginModelBase) getPage()
319: .getModel();
320: fAdditionalTable.setInput(model.getPluginBase());
321: TablePart part = getTablePart();
322: part.setButtonEnabled(0, model.isEditable());
323: part.setButtonEnabled(1, false);
324: part.setButtonEnabled(2, false);
325: part.setButtonEnabled(3, false);
326:
327: IBuildModel build = getBuildModel(false);
328: if (build != null)
329: build.addModelChangedListener(this );
330:
331: IResource resource = model.getUnderlyingResource();
332: if (resource == null)
333: return;
334: fProject = resource.getProject();
335: IEclipsePreferences pref = new ProjectScope(fProject)
336: .getNode(PDECore.PLUGIN_ID);
337: if (pref != null) {
338: boolean useRequireBundle = pref.getBoolean(
339: ICoreConstants.RESOLVE_WITH_REQUIRE_BUNDLE,
340: true);
341: fRequireBundleButton.setSelection(useRequireBundle);
342: fImportPackageButton.setSelection(!useRequireBundle);
343: }
344: PDECore.getDefault().getModelManager()
345: .addPluginModelListener(this );
346: } catch (Exception e) {
347: PDEPlugin.logException(e);
348: }
349: }
350:
351: protected void fillContextMenu(IMenuManager manager) {
352: ISelection selection = fAdditionalTable.getSelection();
353: manager.add(fNewAction);
354: manager.add(fOpenAction);
355: manager.add(new Separator());
356:
357: if (!selection.isEmpty())
358: manager.add(fRemoveAction);
359:
360: // Add clipboard operations
361: getPage().getPDEEditor().getContributor()
362: .contextMenuAboutToShow(manager);
363: }
364:
365: public void refresh() {
366: fAdditionalBundles = null;
367: if (!fAdditionalTable.getControl().isDisposed())
368: fAdditionalTable.refresh();
369: super .refresh();
370: }
371:
372: protected void buttonSelected(int index) {
373: switch (index) {
374: case ADD_INDEX:
375: handleNew();
376: break;
377: case REMOVE_INDEX:
378: handleRemove();
379: break;
380: case UP_INDEX:
381: handleUp();
382: break;
383: case DOWN_INDEX:
384: handleDown();
385: break;
386: }
387: }
388:
389: protected void handleDoubleClick(IStructuredSelection sel) {
390: handleOpen(sel);
391: }
392:
393: private void handleOpen(ISelection sel) {
394: if (sel instanceof IStructuredSelection) {
395: IStructuredSelection ssel = (IStructuredSelection) sel;
396: if (ssel.size() == 1) {
397: Object obj = ssel.getFirstElement();
398: IPluginModelBase base = PluginRegistry
399: .findModel((String) obj);
400: if (base != null)
401: ManifestEditor.open(base.getPluginBase(), false);
402: }
403: }
404: }
405:
406: private IBuildModel getBuildModel(boolean createIfMissing) {
407: InputContext context = getPage().getPDEEditor()
408: .getContextManager().findContext(
409: BuildInputContext.CONTEXT_ID);
410: if (context == null) {
411: if (createIfMissing) {
412: IFile buildFile = getPage().getPDEEditor()
413: .getCommonProject().getFile("build.properties"); //$NON-NLS-1$
414: try {
415: buildFile.create(new ByteArrayInputStream(
416: new byte[0]), true,
417: new NullProgressMonitor());
418: } catch (CoreException e) {
419: return null;
420: }
421: FileEditorInput in = new FileEditorInput(buildFile);
422: PDEFormEditor editor = getPage().getPDEEditor();
423: context = new BuildInputContext(getPage()
424: .getPDEEditor(), in, false);
425: editor.getContextManager().putContext(in, context);
426: } else
427: return null;
428: }
429: return (IBuildModel) context.getModel();
430: }
431:
432: private void makeActions() {
433: fNewAction = new Action(ADD) {
434: public void run() {
435: handleNew();
436: }
437: };
438:
439: fOpenAction = new Action(OPEN) {
440: public void run() {
441: handleOpen(fAdditionalTable.getSelection());
442: }
443: };
444:
445: fRemoveAction = new Action(REMOVE) {
446: public void run() {
447: handleRemove();
448: }
449: };
450: }
451:
452: private void handleNew() {
453: PluginSelectionDialog dialog = new PluginSelectionDialog(
454: PDEPlugin.getActiveWorkbenchShell(),
455: getAvailablePlugins(), true);
456: dialog.create();
457: if (dialog.open() == Window.OK) {
458: IBuildModel model = getBuildModel(true);
459: IBuild build = model.getBuild();
460: IBuildEntry entry = build
461: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
462: try {
463: if (entry == null) {
464: entry = model.getFactory().createEntry(
465: IBuildEntry.SECONDARY_DEPENDENCIES);
466: build.add(entry);
467: }
468: Object[] models = dialog.getResult();
469:
470: for (int i = 0; i < models.length; i++) {
471: IPluginModel pmodel = (IPluginModel) models[i];
472: entry.addToken(pmodel.getPlugin().getId());
473: }
474: markDirty();
475: } catch (CoreException e) {
476: PDEPlugin.logException(e);
477: }
478: }
479: }
480:
481: private IPluginModelBase[] getAvailablePlugins() {
482: IPluginModelBase[] plugins = PluginRegistry
483: .getActiveModels(false);
484: HashSet currentPlugins = new HashSet(
485: (fAdditionalBundles == null) ? new Vector(1)
486: : fAdditionalBundles);
487: IProject currentProj = getPage().getPDEEditor()
488: .getCommonProject();
489: IPluginModelBase model = PluginRegistry.findModel(currentProj);
490: if (model != null) {
491: currentPlugins.add(model.getPluginBase().getId());
492: }
493:
494: ArrayList result = new ArrayList();
495: for (int i = 0; i < plugins.length; i++) {
496: if (!currentPlugins.contains(plugins[i].getPluginBase()
497: .getId()))
498: result.add(plugins[i]);
499: }
500: return (IPluginModelBase[]) result
501: .toArray(new IPluginModelBase[result.size()]);
502: }
503:
504: private void handleRemove() {
505: IStructuredSelection ssel = (IStructuredSelection) fAdditionalTable
506: .getSelection();
507:
508: IBuild build = getBuildModel(false).getBuild();
509: IBuildEntry entry = build
510: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
511: Iterator it = ssel.iterator();
512: try {
513: while (it.hasNext()) {
514: String pluginName = (String) it.next();
515: entry.removeToken(pluginName);
516: }
517: if (entry.getTokens().length == 0)
518: build.remove(entry);
519: } catch (CoreException e) {
520: PDEPlugin.logException(e);
521: }
522: refresh();
523: markDirty();
524: }
525:
526: /* (non-Javadoc)
527: * @see org.eclipse.pde.internal.ui.editor.TableSection#selectionChanged(org.eclipse.jface.viewers.IStructuredSelection)
528: */
529: protected void selectionChanged(IStructuredSelection sel) {
530: // Update global selection
531: getPage().getPDEEditor().setSelection(sel);
532: updateButtons();
533: }
534:
535: private void updateButtons() {
536: TablePart part = getTablePart();
537: Table table = fAdditionalTable.getTable();
538: int index = table.getSelectionIndex();
539: part.setButtonEnabled(1, index != -1);
540: updateUpDownButtons();
541: }
542:
543: public void modelChanged(IModelChangedEvent event) {
544: if (event.getChangeType() == IModelChangedEvent.WORLD_CHANGED) {
545: markStale();
546: return;
547: }
548: Object changedObject = event.getChangedObjects()[0];
549: if ((changedObject instanceof IBuildEntry && ((IBuildEntry) changedObject)
550: .getName().equals(IBuildEntry.SECONDARY_DEPENDENCIES))) {
551: refresh();
552: }
553: }
554:
555: /* (non-Javadoc)
556: * @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String)
557: */
558: public boolean doGlobalAction(String actionId) {
559:
560: if (!isEditable()) {
561: return false;
562: }
563:
564: if (actionId.equals(ActionFactory.DELETE.getId())) {
565: handleRemove();
566: return true;
567: }
568: if (actionId.equals(ActionFactory.CUT.getId())) {
569: // delete here and let the editor transfer
570: // the selection to the clipboard
571: handleRemove();
572: return false;
573: }
574: if (actionId.equals(ActionFactory.PASTE.getId())) {
575: doPaste();
576: return true;
577: }
578: return false;
579:
580: }
581:
582: /* (non-Javadoc)
583: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canPaste(java.lang.Object, java.lang.Object[])
584: */
585: protected boolean canPaste(Object targetObject,
586: Object[] sourceObjects) {
587: HashSet secondaryDepSet = null;
588: // Only String objects representing non-duplicate secondary
589: // dependencies can be pasted
590: for (int i = 0; i < sourceObjects.length; i++) {
591: // Only String objects are allowed
592: if ((sourceObjects[i] instanceof String) == false) {
593: return false;
594: }
595: // Get the current secondary dependencies and store them to
596: // assist in searching
597: if (secondaryDepSet == null) {
598: secondaryDepSet = createSecondaryDepSet();
599: }
600: // No duplicate secondary dependencies allowed
601: String secondaryDep = (String) sourceObjects[i];
602: if (secondaryDepSet.contains(secondaryDep)) {
603: return false;
604: }
605: }
606: return true;
607: }
608:
609: /**
610: * @return
611: */
612: private HashSet createSecondaryDepSet() {
613: HashSet secondaryDepSet = new HashSet();
614: // Get the build model
615: IBuildModel buildModel = getBuildModel(true);
616: // Ensure the build model is defined
617: if (buildModel == null) {
618: return secondaryDepSet;
619: }
620: // Get the root build object
621: IBuild build = buildModel.getBuild();
622: // Get the secondary dependencies build entry
623: IBuildEntry entry = build
624: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
625: // Ensure the build entry is defined
626: if (entry == null) {
627: return secondaryDepSet;
628: }
629: // Get the token values for the build entry
630: String[] tokens = entry.getTokens();
631: // Ensure we have token values
632: if (tokens.length == 0) {
633: return secondaryDepSet;
634: }
635: // Add all token values to the dependencies set
636: for (int i = 0; i < tokens.length; i++) {
637: secondaryDepSet.add(tokens[i]);
638: }
639: return secondaryDepSet;
640: }
641:
642: /* (non-Javadoc)
643: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doPaste(java.lang.Object, java.lang.Object[])
644: */
645: protected void doPaste(Object targetObject, Object[] sourceObjects) {
646: // Get the build model
647: IBuildModel buildModel = getBuildModel(true);
648: // Ensure the build model is defined
649: if (buildModel == null) {
650: return;
651: }
652: // Get the root build object
653: IBuild build = buildModel.getBuild();
654: // Get the secondary dependencies build entry
655: IBuildEntry entry = build
656: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
657: try {
658: // Paste all source objects
659: for (int i = 0; i < sourceObjects.length; i++) {
660: Object sourceObject = sourceObjects[i];
661: if (sourceObject instanceof String) {
662: // If the build entry is not defined, create one
663: if (entry == null) {
664: entry = buildModel.getFactory().createEntry(
665: IBuildEntry.SECONDARY_DEPENDENCIES);
666: build.add(entry);
667: }
668: // Add the source object token value to the build entry
669: entry.addToken((String) sourceObject);
670: }
671: }
672: } catch (CoreException e) {
673: PDEPlugin.logException(e);
674: }
675: }
676:
677: protected void doAddDependencies() {
678: IBaseModel model = getPage().getModel();
679: if (model instanceof IBundlePluginModelBase) {
680: IProject proj = getPage().getPDEEditor().getCommonProject();
681: IBundlePluginModelBase bmodel = ((IBundlePluginModelBase) model);
682: AddNewDependenciesAction action = new AddNewDependenciesAction(
683: proj, bmodel);
684: action.run();
685: }
686: }
687:
688: public void dispose() {
689: IPluginModelBase model = (IPluginModelBase) getPage()
690: .getModel();
691: if (model != null)
692: model.removeModelChangedListener(this );
693: PDECore.getDefault().getModelManager()
694: .removePluginModelListener(this );
695: super .dispose();
696: }
697:
698: public void modelsChanged(PluginModelDelta delta) {
699: fAdditionalBundles = null;
700: final Control control = fAdditionalTable.getControl();
701: if (!control.isDisposed()) {
702: control.getDisplay().asyncExec(new Runnable() {
703: public void run() {
704: if (!control.isDisposed())
705: fAdditionalTable.refresh();
706: }
707: });
708: }
709: }
710:
711: private void handleUp() {
712: movePlugins(-1);
713: }
714:
715: private void handleDown() {
716: movePlugins(1);
717: }
718:
719: private void updateUpDownButtons() {
720: TablePart tablePart = getTablePart();
721: if (fSortAction.isChecked()) {
722: tablePart.setButtonEnabled(UP_INDEX, false);
723: tablePart.setButtonEnabled(DOWN_INDEX, false);
724: return;
725: }
726: Table table = fAdditionalTable.getTable();
727: int index = table.getSelectionIndex();
728: int totalElems = table.getItemCount();
729: boolean canMove = totalElems > 1
730: && table.getSelectionCount() == 1;
731: tablePart.setButtonEnabled(2, canMove && index > 0);
732: tablePart.setButtonEnabled(3, canMove && index >= 0
733: && index < totalElems - 1);
734: }
735:
736: private void movePlugins(int newOffset) {
737: int index = fAdditionalTable.getTable().getSelectionIndex();
738: if (index == -1)
739: return; // safety check
740: IBuildModel model = getBuildModel(false);
741: if (model != null) {
742: IBuild build = model.getBuild();
743: IBuildEntry entry = build
744: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
745: if (entry instanceof org.eclipse.pde.internal.core.text.build.BuildEntry)
746: ((org.eclipse.pde.internal.core.text.build.BuildEntry) entry)
747: .swap(index, index + newOffset);
748: }
749: updateButtons();
750: }
751:
752: public void propertyChange(PropertyChangeEvent event) {
753: if (fSortAction.equals(event.getSource())
754: && IAction.RESULT.equals(event.getProperty())) {
755: updateUpDownButtons();
756: }
757: }
758:
759: protected boolean createCount() {
760: return true;
761: }
762:
763: /* (non-Javadoc)
764: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#isDragAndDropEnabled()
765: */
766: protected boolean isDragAndDropEnabled() {
767: return true;
768: }
769:
770: /* (non-Javadoc)
771: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canDragMove(java.lang.Object[])
772: */
773: public boolean canDragMove(Object[] sourceObjects) {
774: if (validateDragMoveSanity(sourceObjects) == false) {
775: return false;
776: } else if (isTreeViewerSorted()) {
777: return false;
778: }
779: return true;
780: }
781:
782: /**
783: * @param sourceObjects
784: * @return
785: */
786: private boolean validateDragMoveSanity(Object[] sourceObjects) {
787: // Validate source
788: if (sourceObjects == null) {
789: // No objects
790: return false;
791: } else if (sourceObjects.length != 1) {
792: // Multiple selection not supported
793: return false;
794: } else if ((sourceObjects[0] instanceof String) == false) {
795: // Must be the right type
796: return false;
797: }
798: return true;
799: }
800:
801: /* (non-Javadoc)
802: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canDropMove(java.lang.Object, java.lang.Object[], int)
803: */
804: public boolean canDropMove(Object targetObject,
805: Object[] sourceObjects, int targetLocation) {
806: // Sanity check
807: if (validateDropMoveSanity(targetObject, sourceObjects) == false) {
808: return false;
809: }
810: // Multiple selection not supported
811: String sourcePlugin = (String) sourceObjects[0];
812: String targetPlugin = (String) targetObject;
813: // Get the secondary dependencies build entry
814: BuildEntry entry = getSecondaryDepBuildEntry();
815: // Validate entry
816: if (entry == null) {
817: return false;
818: }
819: // Validate move
820: if (targetLocation == ViewerDropAdapter.LOCATION_BEFORE) {
821: // Get the previous plugin of the target
822: String previousPlugin = entry
823: .getPreviousToken(targetPlugin);
824: // Ensure the previous token is not the source
825: if (sourcePlugin.equals(previousPlugin)) {
826: return false;
827: }
828: return true;
829: } else if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) {
830: // Get the next plugin of the target
831: String nextPlugin = entry.getNextToken(targetPlugin);
832: // Ensure the next plugin is not the source
833: if (sourcePlugin.equals(nextPlugin)) {
834: return false;
835: }
836: return true;
837: } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) {
838: // Not supported
839: return false;
840: }
841:
842: return false;
843: }
844:
845: /**
846: * @return
847: */
848: private BuildEntry getSecondaryDepBuildEntry() {
849: // Get the build model
850: IBuildModel buildModel = getBuildModel(true);
851: // Ensure the build model is defined
852: if (buildModel == null) {
853: return null;
854: }
855: // Get the root build object
856: IBuild build = buildModel.getBuild();
857: // Ensure we have a root
858: if (build == null) {
859: return null;
860: }
861: // Get the secondary dependencies build entry
862: IBuildEntry entry = build
863: .getEntry(IBuildEntry.SECONDARY_DEPENDENCIES);
864: // Ensure we have the concrete text entry
865: if ((entry instanceof BuildEntry) == false) {
866: return null;
867: }
868: return (BuildEntry) entry;
869: }
870:
871: /**
872: * @param targetObject
873: * @param sourceObjects
874: * @return
875: */
876: private boolean validateDropMoveSanity(Object targetObject,
877: Object[] sourceObjects) {
878: // Validate target object
879: if ((targetObject instanceof String) == false) {
880: return false;
881: }
882: // Validate source objects
883: if (validateDragMoveSanity(sourceObjects) == false) {
884: return false;
885: }
886: return true;
887: }
888:
889: /* (non-Javadoc)
890: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doDropMove(java.lang.Object, java.lang.Object[], int)
891: */
892: public void doDropMove(Object targetObject, Object[] sourceObjects,
893: int targetLocation) {
894: // Sanity check
895: if (validateDropMoveSanity(targetObject, sourceObjects) == false) {
896: Display.getDefault().beep();
897: return;
898: }
899: // Multiple selection not supported
900: String sourcePlugin = (String) sourceObjects[0];
901: String targetPlugin = (String) targetObject;
902: // Validate move
903: if ((targetLocation == ViewerDropAdapter.LOCATION_BEFORE)
904: || (targetLocation == ViewerDropAdapter.LOCATION_AFTER)) {
905: // Do move
906: doDropMove(sourcePlugin, targetPlugin, targetLocation);
907: } else if (targetLocation == ViewerDropAdapter.LOCATION_ON) {
908: // Not supported
909: }
910: }
911:
912: /**
913: * @param sourcePlugin
914: * @param targetPlugin
915: * @param targetLocation
916: */
917: private void doDropMove(String sourcePlugin, String targetPlugin,
918: int targetLocation) {
919: // Remove the original source object
920: // Normally we remove the original source object after inserting the
921: // serialized source object; however, the plug-ins are removed via ID
922: // and having both objects with the same ID co-existing will confound
923: // the remove operation
924: doDragRemove();
925: // Get the secondary dependencies build entry
926: BuildEntry entry = getSecondaryDepBuildEntry();
927: // Validate entry
928: if (entry == null) {
929: return;
930: }
931: // Get the index of the target
932: int index = entry.getIndexOf(targetPlugin);
933: // Ensure the target index was found
934: if (index == -1) {
935: return;
936: }
937: // Determine the location index
938: int targetIndex = index;
939: if (targetLocation == ViewerDropAdapter.LOCATION_AFTER) {
940: targetIndex++;
941: }
942: // Add source as sibling of target
943: entry.addToken(sourcePlugin, targetIndex);
944: }
945:
946: /**
947: *
948: */
949: private void doDragRemove() {
950: // Get the secondary dependencies build entry
951: BuildEntry entry = getSecondaryDepBuildEntry();
952: // Validate entry
953: if (entry == null) {
954: return;
955: }
956: // Retrieve the original non-serialized source objects dragged initially
957: Object[] sourceObjects = getDragSourceObjects();
958: // Validate source objects
959: if (validateDragMoveSanity(sourceObjects) == false) {
960: return;
961: }
962: // Remove the library
963: String sourcePlugin = (String) sourceObjects[0];
964: try {
965: entry.removeToken(sourcePlugin);
966: } catch (CoreException e) {
967: PDEPlugin.logException(e);
968: }
969: }
970:
971: /**
972: * @return
973: */
974: private boolean isTreeViewerSorted() {
975: if (fSortAction == null) {
976: return false;
977: }
978: return fSortAction.isChecked();
979: }
980: }
|