001: /*******************************************************************************
002: * Copyright (c) 2003, 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: * Bartosz Michalik <bartosz.michalik@gmail.com> - bug 181878
011: *******************************************************************************/package org.eclipse.pde.internal.ui.editor.site;
012:
013: import java.util.ArrayList;
014: import java.util.HashSet;
015: import java.util.Iterator;
016: import java.util.Set;
017:
018: import org.eclipse.core.runtime.CoreException;
019: import org.eclipse.jface.action.Action;
020: import org.eclipse.jface.action.IMenuManager;
021: import org.eclipse.jface.action.Separator;
022: import org.eclipse.jface.viewers.ISelection;
023: import org.eclipse.jface.viewers.IStructuredSelection;
024: import org.eclipse.jface.viewers.ITreeContentProvider;
025: import org.eclipse.jface.viewers.LabelProvider;
026: import org.eclipse.jface.viewers.StructuredSelection;
027: import org.eclipse.jface.viewers.TreeViewer;
028: import org.eclipse.jface.viewers.ViewerDropAdapter;
029: import org.eclipse.jface.window.Window;
030: import org.eclipse.osgi.util.NLS;
031: import org.eclipse.pde.core.IModelChangedEvent;
032: import org.eclipse.pde.internal.core.FeatureModelManager;
033: import org.eclipse.pde.internal.core.IFeatureModelDelta;
034: import org.eclipse.pde.internal.core.IFeatureModelListener;
035: import org.eclipse.pde.internal.core.PDECore;
036: import org.eclipse.pde.internal.core.ifeature.IFeature;
037: import org.eclipse.pde.internal.core.ifeature.IFeatureImport;
038: import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
039: import org.eclipse.pde.internal.core.isite.ISiteCategory;
040: import org.eclipse.pde.internal.core.isite.ISiteCategoryDefinition;
041: import org.eclipse.pde.internal.core.isite.ISiteFeature;
042: import org.eclipse.pde.internal.core.isite.ISiteModel;
043: import org.eclipse.pde.internal.ui.PDEPlugin;
044: import org.eclipse.pde.internal.ui.PDEUIMessages;
045: import org.eclipse.pde.internal.ui.editor.ModelDataTransfer;
046: import org.eclipse.pde.internal.ui.editor.PDEFormPage;
047: import org.eclipse.pde.internal.ui.editor.TreeSection;
048: import org.eclipse.pde.internal.ui.editor.feature.FeatureEditor;
049: import org.eclipse.pde.internal.ui.elements.DefaultContentProvider;
050: import org.eclipse.pde.internal.ui.parts.TreePart;
051: import org.eclipse.pde.internal.ui.wizards.FeatureSelectionDialog;
052: import org.eclipse.swt.SWT;
053: import org.eclipse.swt.custom.BusyIndicator;
054: import org.eclipse.swt.dnd.DND;
055: import org.eclipse.swt.dnd.DragSourceEvent;
056: import org.eclipse.swt.dnd.DragSourceListener;
057: import org.eclipse.swt.dnd.DropTargetEvent;
058: import org.eclipse.swt.dnd.Transfer;
059: import org.eclipse.swt.dnd.TransferData;
060: import org.eclipse.swt.graphics.Point;
061: import org.eclipse.swt.graphics.Rectangle;
062: import org.eclipse.swt.widgets.Composite;
063: import org.eclipse.swt.widgets.Control;
064: import org.eclipse.swt.widgets.Item;
065: import org.eclipse.ui.actions.ActionFactory;
066: import org.eclipse.ui.forms.widgets.FormToolkit;
067: import org.eclipse.ui.forms.widgets.Section;
068: import org.osgi.framework.Version;
069:
070: public class CategorySection extends TreeSection implements
071: IFeatureModelListener {
072: private static final int BUTTON_ADD_CATEGORY = 0;
073:
074: private static final int BUTTON_ADD_FEATURE = 1;
075:
076: private static final int BUTTON_IMPORT_ENVIRONMENT = 3;
077:
078: private static final int BUTTON_BUILD_FEATURE = 5;
079:
080: private static final int BUTTON_BUILD_ALL = 6;
081:
082: private static int newCategoryCounter;
083:
084: private ISiteModel fModel;
085:
086: private TreePart fCategoryTreePart;
087:
088: private TreeViewer fCategoryViewer;
089:
090: private LabelProvider fSiteLabelProvider;
091:
092: private ISiteFeature[] cachedFeatures;
093:
094: private IStructuredSelection cachedSelection;
095:
096: class CategoryContentProvider extends DefaultContentProvider
097: implements ITreeContentProvider {
098: public Object[] getElements(Object inputElement) {
099: // model = (ISite) inputElement;
100: ArrayList result = new ArrayList();
101: ISiteCategoryDefinition[] catDefs = fModel.getSite()
102: .getCategoryDefinitions();
103: for (int i = 0; i < catDefs.length; i++) {
104: result.add(catDefs[i]);
105: }
106: ISiteFeature[] features = fModel.getSite().getFeatures();
107: for (int i = 0; i < features.length; i++) {
108: if (features[i].getCategories().length == 0)
109: result
110: .add(new SiteFeatureAdapter(null,
111: features[i]));
112: }
113: return result.toArray();
114: }
115:
116: public Object[] getChildren(Object parent) {
117: if (parent instanceof ISiteCategoryDefinition) {
118: ISiteCategoryDefinition catDef = (ISiteCategoryDefinition) parent;
119: ISiteFeature[] features = fModel.getSite()
120: .getFeatures();
121: HashSet result = new HashSet();
122: for (int i = 0; i < features.length; i++) {
123: ISiteCategory[] cats = features[i].getCategories();
124: for (int j = 0; j < cats.length; j++) {
125: if (cats[j].getDefinition() != null
126: && cats[j].getDefinition().equals(
127: catDef)) {
128: result.add(new SiteFeatureAdapter(cats[j]
129: .getName(), features[i]));
130: }
131: }
132: }
133: return result.toArray();
134: }
135: return new Object[0];
136: }
137:
138: public Object getParent(Object element) {
139: return null;
140: }
141:
142: public boolean hasChildren(Object element) {
143: if (element instanceof ISiteCategoryDefinition) {
144: ISiteCategoryDefinition catDef = (ISiteCategoryDefinition) element;
145: ISiteFeature[] features = fModel.getSite()
146: .getFeatures();
147: for (int i = 0; i < features.length; i++) {
148: ISiteCategory[] cats = features[i].getCategories();
149: for (int j = 0; j < cats.length; j++) {
150: if (cats[j].getDefinition() != null
151: && cats[j].getDefinition().equals(
152: catDef)) {
153: return true;
154: }
155: }
156: }
157: }
158: return false;
159: }
160: }
161:
162: public CategorySection(PDEFormPage formPage, Composite parent) {
163: super (formPage, parent, Section.DESCRIPTION, new String[] {
164: PDEUIMessages.CategorySection_new,
165: PDEUIMessages.CategorySection_add, null,
166: PDEUIMessages.CategorySection_environment, null,
167: PDEUIMessages.CategorySection_build,
168: PDEUIMessages.CategorySection_buildAll });
169: getSection().setText(PDEUIMessages.CategorySection_title);
170: getSection().setDescription(PDEUIMessages.CategorySection_desc);
171: }
172:
173: /*
174: * (non-Javadoc)
175: *
176: * @see org.eclipse.update.ui.forms.internal.FormSection#createClient(org.eclipse.swt.widgets.Composite,
177: * org.eclipse.update.ui.forms.internal.FormWidgetFactory)
178: */
179: public void createClient(Section section, FormToolkit toolkit) {
180: fModel = (ISiteModel) getPage().getModel();
181: fModel.addModelChangedListener(this );
182:
183: Composite container = createClientContainer(section, 2, toolkit);
184: createViewerPartControl(container, SWT.MULTI, 2, toolkit);
185: fCategoryTreePart = getTreePart();
186: fCategoryViewer = fCategoryTreePart.getTreeViewer();
187: fCategoryViewer
188: .setContentProvider(new CategoryContentProvider());
189: fSiteLabelProvider = new SiteLabelProvider();
190: fCategoryViewer.setLabelProvider(fSiteLabelProvider);
191:
192: fCategoryViewer.setInput(fModel.getSite());
193: int ops = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_DEFAULT;
194: Transfer[] transfers = new Transfer[] { ModelDataTransfer
195: .getInstance() };
196: if (isEditable()) {
197: fCategoryViewer.addDropSupport(ops, transfers,
198: new ViewerDropAdapter(fCategoryViewer) {
199: public void dragEnter(DropTargetEvent event) {
200: Object target = determineTarget(event);
201: if (target == null
202: && event.detail == DND.DROP_COPY) {
203: event.detail = DND.DROP_MOVE;
204: }
205: super .dragEnter(event);
206: }
207:
208: /*
209: * (non-Javadoc)
210: *
211: * @see org.eclipse.jface.viewers.ViewerDropAdapter#dragOperationChanged(org.eclipse.swt.dnd.DropTargetEvent)
212: */
213: public void dragOperationChanged(
214: DropTargetEvent event) {
215: Object target = determineTarget(event);
216: if (target == null
217: && event.detail == DND.DROP_COPY) {
218: event.detail = DND.DROP_MOVE;
219: }
220: super .dragOperationChanged(event);
221: }
222:
223: /*
224: * (non-Javadoc)
225: *
226: * @see org.eclipse.jface.viewers.ViewerDropAdapter#dragOver(org.eclipse.swt.dnd.DropTargetEvent)
227: */
228: public void dragOver(DropTargetEvent event) {
229: Object target = determineTarget(event);
230: if (target == null
231: && event.detail == DND.DROP_COPY) {
232: event.detail = DND.DROP_MOVE;
233: }
234: super .dragOver(event);
235: }
236:
237: /**
238: * Returns the position of the given event's coordinates
239: * relative to its target. The position is determined to
240: * be before, after, or on the item, based on some
241: * threshold value.
242: *
243: * @param event
244: * the event
245: * @return one of the <code>LOCATION_* </code>
246: * constants defined in this class
247: */
248: protected int determineLocation(
249: DropTargetEvent event) {
250: if (!(event.item instanceof Item)) {
251: return LOCATION_NONE;
252: }
253: Item item = (Item) event.item;
254: Point coordinates = new Point(event.x,
255: event.y);
256: coordinates = getViewer().getControl()
257: .toControl(coordinates);
258: if (item != null) {
259: Rectangle bounds = getBounds(item);
260: if (bounds == null) {
261: return LOCATION_NONE;
262: }
263: }
264: return LOCATION_ON;
265: }
266:
267: public boolean performDrop(Object data) {
268: if (!(data instanceof Object[]))
269: return false;
270: Object target = getCurrentTarget();
271:
272: int op = getCurrentOperation();
273: Object[] objects = (Object[]) data;
274: if (objects.length > 0
275: && objects[0] instanceof SiteFeatureAdapter) {
276: if (op == DND.DROP_COPY
277: && target != null) {
278: copyFeature(
279: (SiteFeatureAdapter) objects[0],
280: target);
281: } else {
282: moveFeature(
283: (SiteFeatureAdapter) objects[0],
284: target);
285: }
286: return true;
287: }
288: return false;
289: }
290:
291: public boolean validateDrop(Object target,
292: int operation, TransferData transferType) {
293: return (target instanceof ISiteCategoryDefinition || target == null);
294: }
295:
296: });
297: }
298:
299: fCategoryViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY,
300: transfers, new DragSourceListener() {
301: public void dragStart(DragSourceEvent event) {
302: IStructuredSelection ssel = (IStructuredSelection) fCategoryViewer
303: .getSelection();
304: if (ssel == null
305: || ssel.isEmpty()
306: || !(ssel.getFirstElement() instanceof SiteFeatureAdapter)) {
307: event.doit = false;
308: }
309: }
310:
311: public void dragSetData(DragSourceEvent event) {
312: IStructuredSelection ssel = (IStructuredSelection) fCategoryViewer
313: .getSelection();
314: event.data = ssel.toArray();
315: }
316:
317: public void dragFinished(DragSourceEvent event) {
318: }
319: });
320:
321: fCategoryTreePart.setButtonEnabled(BUTTON_ADD_CATEGORY,
322: isEditable());
323: fCategoryTreePart.setButtonEnabled(BUTTON_ADD_FEATURE,
324: isEditable());
325: fCategoryTreePart.setButtonEnabled(BUTTON_BUILD_FEATURE,
326: isEditable());
327: fCategoryTreePart.setButtonEnabled(BUTTON_BUILD_ALL,
328: isEditable());
329:
330: // fCategoryViewer.expandAll();
331: toolkit.paintBordersFor(container);
332: section.setClient(container);
333: initialize();
334: }
335:
336: private boolean categoryExists(String name) {
337: ISiteCategoryDefinition[] defs = fModel.getSite()
338: .getCategoryDefinitions();
339: for (int i = 0; i < defs.length; i++) {
340: ISiteCategoryDefinition def = defs[i];
341: String dname = def.getName();
342: if (dname != null && dname.equals(name))
343: return true;
344: }
345: return false;
346: }
347:
348: private void copyFeature(SiteFeatureAdapter adapter, Object target) {
349: ISiteFeature feature = findRealFeature(adapter);
350: if (feature == null) {
351: return;
352: }
353: /*
354: * if (adapter.category == null) { moveFeature(adapter, target); } else
355: */if (target != null
356: && target instanceof ISiteCategoryDefinition) {
357: addCategory(feature, ((ISiteCategoryDefinition) target)
358: .getName());
359: }
360: }
361:
362: private void addCategory(ISiteFeature aFeature, String catName) {
363: try {
364: if (aFeature == null)
365: return;
366: ISiteCategory[] cats = aFeature.getCategories();
367: for (int j = 0; j < cats.length; j++) {
368: if (cats[j].getName().equals(catName))
369: return;
370: }
371: ISiteCategory cat = fModel.getFactory().createCategory(
372: aFeature);
373: cat.setName(catName);
374: expandCategory(catName);
375: aFeature.addCategories(new ISiteCategory[] { cat });
376: } catch (CoreException e) {
377: }
378: }
379:
380: private void moveFeature(SiteFeatureAdapter adapter, Object target) {
381: ISiteFeature feature = findRealFeature(adapter);
382: if (feature == null) {
383: return;
384: }
385: if (adapter.category != null) {
386: removeCategory(feature, adapter.category);
387: }
388: if (target != null && target instanceof ISiteCategoryDefinition) {
389: addCategory(feature, ((ISiteCategoryDefinition) target)
390: .getName());
391: }
392: }
393:
394: protected void buttonSelected(int index) {
395: switch (index) {
396: case BUTTON_ADD_CATEGORY:
397: handleAddCategoryDefinition();
398: break;
399: case BUTTON_ADD_FEATURE:
400: handleNewFeature();
401: break;
402: case BUTTON_BUILD_FEATURE:
403: handleBuild();
404: break;
405: case BUTTON_BUILD_ALL:
406: ((SiteEditor) getPage().getPDEEditor()).handleBuild(fModel
407: .getSite().getFeatures());
408: break;
409: case BUTTON_IMPORT_ENVIRONMENT:
410: handleImportEnvironment();
411: }
412: }
413:
414: protected void handleDoubleClick(IStructuredSelection ssel) {
415: super .handleDoubleClick(ssel);
416: Object selected = ssel.getFirstElement();
417: if (selected instanceof SiteFeatureAdapter) {
418: IFeature feature = findFeature(((SiteFeatureAdapter) selected).feature);
419: FeatureEditor.openFeatureEditor(feature);
420: }
421: }
422:
423: protected void selectionChanged(IStructuredSelection selection) {
424: getPage().getPDEEditor().setSelection(selection);
425: updateButtons();
426: }
427:
428: private void handleAddCategoryDefinition() {
429: String name = NLS.bind(
430: PDEUIMessages.CategorySection_newCategoryName, Integer
431: .toString(++newCategoryCounter));
432: while (categoryExists(name)) {
433: name = NLS.bind(
434: PDEUIMessages.CategorySection_newCategoryName,
435: Integer.toString(++newCategoryCounter));
436: }
437: String label = NLS.bind(
438: PDEUIMessages.CategorySection_newCategoryLabel, Integer
439: .toString(newCategoryCounter));
440: ISiteCategoryDefinition categoryDef = fModel.getFactory()
441: .createCategoryDefinition();
442: try {
443: categoryDef.setName(name);
444: categoryDef.setLabel(label);
445: fModel.getSite().addCategoryDefinitions(
446: new ISiteCategoryDefinition[] { categoryDef });
447: } catch (CoreException e) {
448: PDEPlugin.logException(e);
449: }
450: fCategoryViewer.setSelection(new StructuredSelection(
451: categoryDef), true);
452: }
453:
454: private boolean handleRemove() {
455: IStructuredSelection ssel = (IStructuredSelection) fCategoryViewer
456: .getSelection();
457: Iterator iterator = ssel.iterator();
458: boolean success = true;
459: Set removedCategories = new HashSet();
460: while (iterator.hasNext()) {
461: Object object = iterator.next();
462: if (object == null)
463: continue;
464: if (object instanceof ISiteCategoryDefinition) {
465: if (!handleRemoveCategoryDefinition((ISiteCategoryDefinition) object)) {
466: success = false;
467: }
468: } else {
469: //check if some of features was not removed during category removal
470: SiteFeatureAdapter fa = (SiteFeatureAdapter) object;
471: if (removedCategories.contains(fa.category))
472: continue;
473:
474: if (!handleRemoveSiteFeatureAdapter(fa)) {
475: success = false;
476: }
477: }
478: }
479: return success;
480: }
481:
482: private boolean handleRemoveCategoryDefinition(
483: ISiteCategoryDefinition catDef) {
484: try {
485: Object[] children = ((CategoryContentProvider) fCategoryViewer
486: .getContentProvider()).getChildren(catDef);
487: for (int i = 0; i < children.length; i++) {
488: SiteFeatureAdapter adapter = (SiteFeatureAdapter) children[i];
489: ISiteCategory[] cats = adapter.feature.getCategories();
490: for (int j = 0; j < cats.length; j++) {
491: if (adapter.category.equals(cats[j].getName()))
492: adapter.feature
493: .removeCategories(new ISiteCategory[] { cats[j] });
494: }
495: if (adapter.feature.getCategories().length == 0) {
496: fModel.getSite().removeFeatures(
497: new ISiteFeature[] { adapter.feature });
498: }
499: }
500: fModel.getSite().removeCategoryDefinitions(
501: new ISiteCategoryDefinition[] { catDef });
502: return true;
503: } catch (CoreException e) {
504: }
505: return false;
506: }
507:
508: private boolean handleRemoveSiteFeatureAdapter(
509: SiteFeatureAdapter adapter) {
510: try {
511: ISiteFeature feature = adapter.feature;
512: if (adapter.category == null) {
513: fModel.getSite().removeFeatures(
514: new ISiteFeature[] { feature });
515: } else {
516: removeCategory(feature, adapter.category);
517: if (feature.getCategories().length == 0)
518: fModel.getSite().removeFeatures(
519: new ISiteFeature[] { feature });
520: }
521: return true;
522: } catch (CoreException e) {
523: }
524: return false;
525: }
526:
527: private void removeCategory(ISiteFeature aFeature, String catName) {
528: try {
529: if (aFeature == null)
530: return;
531: ISiteCategory[] cats = aFeature.getCategories();
532: for (int i = 0; i < cats.length; i++) {
533: if (catName.equals(cats[i].getName()))
534: aFeature
535: .removeCategories(new ISiteCategory[] { cats[i] });
536: }
537: } catch (CoreException e) {
538: }
539: }
540:
541: private ISiteFeature findRealFeature(SiteFeatureAdapter adapter) {
542: ISiteFeature featureCopy = adapter.feature;
543: ISiteFeature[] features = fModel.getSite().getFeatures();
544: for (int i = 0; i < features.length; i++) {
545: if (features[i].getId().equals(featureCopy.getId())
546: && features[i].getVersion().equals(
547: featureCopy.getVersion())) {
548: return features[i];
549: }
550: }
551: return null;
552: }
553:
554: public void dispose() {
555: super .dispose();
556: FeatureModelManager mng = PDECore.getDefault()
557: .getFeatureModelManager();
558: mng.removeFeatureModelListener(this );
559: fModel.removeModelChangedListener(this );
560: if (fSiteLabelProvider != null)
561: fSiteLabelProvider.dispose();
562: }
563:
564: protected void fillContextMenu(IMenuManager manager) {
565: Action removeAction = new Action(
566: PDEUIMessages.CategorySection_remove) {
567: public void run() {
568: doGlobalAction(ActionFactory.DELETE.getId());
569: }
570: };
571: removeAction.setEnabled(isEditable());
572: manager.add(removeAction);
573: getPage().getPDEEditor().getContributor()
574: .contextMenuAboutToShow(manager);
575:
576: ISelection selection = fCategoryViewer.getSelection();
577: if (!selection.isEmpty()
578: && selection instanceof IStructuredSelection) {
579: final ISiteFeature[] features = getFeaturesFromSelection((IStructuredSelection) selection);
580: if (features.length > 0) {
581: manager.add(new Separator());
582: Action synchronizeAction = new SynchronizePropertiesAction(
583: features, fModel);
584: manager.add(synchronizeAction);
585: Action buildAction = new Action(
586: PDEUIMessages.CategorySection_build) {
587: public void run() {
588: ((SiteEditor) getPage().getPDEEditor())
589: .handleBuild(features);
590: }
591: };
592: buildAction.setEnabled(isEditable());
593: manager.add(buildAction);
594: }
595: }
596: }
597:
598: public boolean doGlobalAction(String actionId) {
599: if (actionId.equals(ActionFactory.CUT.getId())) {
600: handleRemove();
601: return false;
602: }
603: if (actionId.equals(ActionFactory.PASTE.getId())) {
604: doPaste();
605: return true;
606: }
607: if (actionId.equals(ActionFactory.DELETE.getId())) {
608: return handleRemove();
609: }
610: if (actionId.equals(ActionFactory.SELECT_ALL.getId())) {
611: fCategoryViewer.getTree().selectAll();
612: refresh();
613: }
614: return false;
615: }
616:
617: public void refresh() {
618: fCategoryViewer.refresh();
619: updateButtons();
620: super .refresh();
621: }
622:
623: private void updateButtons() {
624: if (!isEditable()) {
625: return;
626: }
627: IStructuredSelection sel = (IStructuredSelection) fCategoryViewer
628: .getSelection();
629: fCategoryTreePart.setButtonEnabled(BUTTON_BUILD_FEATURE,
630: getFeaturesFromSelection(sel).length > 0);
631: int featureCount = fModel.getSite().getFeatures().length;
632: fCategoryTreePart.setButtonEnabled(BUTTON_BUILD_ALL,
633: featureCount > 0);
634: fCategoryTreePart.setButtonEnabled(BUTTON_IMPORT_ENVIRONMENT,
635: featureCount > 0);
636: }
637:
638: public void modelChanged(IModelChangedEvent e) {
639: markStale();
640: }
641:
642: public void initialize() {
643: refresh();
644: FeatureModelManager mng = PDECore.getDefault()
645: .getFeatureModelManager();
646: mng.addFeatureModelListener(this );
647: }
648:
649: /*
650: * (non-Javadoc)
651: *
652: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#doPaste(java.lang.Object,
653: * java.lang.Object[])
654: */
655: protected void doPaste(Object target, Object[] objects) {
656: try {
657: for (int i = 0; i < objects.length; i++) {
658: if (objects[i] instanceof SiteFeatureAdapter) {
659: copyFeature((SiteFeatureAdapter) objects[i], target);
660: } else if (objects[i] instanceof ISiteCategoryDefinition) {
661: fModel
662: .getSite()
663: .addCategoryDefinitions(
664: new ISiteCategoryDefinition[] { (ISiteCategoryDefinition) objects[i] });
665: }
666: }
667: } catch (CoreException e) {
668: }
669: }
670:
671: /*
672: * (non-Javadoc)
673: *
674: * @see org.eclipse.pde.internal.ui.editor.StructuredViewerSection#canPaste(java.lang.Object,
675: * java.lang.Object[])
676: */
677: protected boolean canPaste(Object target, Object[] objects) {
678: if (target == null || target instanceof ISiteCategoryDefinition) {
679: for (int i = 0; i < objects.length; i++) {
680: if (objects[i] instanceof SiteFeatureAdapter)
681: return true;
682: if (objects[i] instanceof ISiteCategoryDefinition) {
683: String name = ((ISiteCategoryDefinition) objects[i])
684: .getName();
685: ISiteCategoryDefinition[] defs = fModel.getSite()
686: .getCategoryDefinitions();
687: for (int j = 0; j < defs.length; j++) {
688: ISiteCategoryDefinition def = defs[j];
689: String dname = def.getName();
690: if (dname != null && dname.equals(name))
691: return false;
692: }
693: return true;
694: }
695: }
696: }
697: return false;
698: }
699:
700: private void handleBuild() {
701: IStructuredSelection sel = (IStructuredSelection) fCategoryViewer
702: .getSelection();
703: ((SiteEditor) getPage().getPDEEditor())
704: .handleBuild(getFeaturesFromSelection(sel));
705: }
706:
707: private ISiteFeature[] getFeaturesFromSelection(
708: IStructuredSelection sel) {
709: if (sel.isEmpty())
710: return new ISiteFeature[0];
711: if (cachedSelection == sel)
712: return cachedFeatures;
713: cachedSelection = sel;
714: ArrayList features = new ArrayList(sel.size());
715: Iterator iterator = sel.iterator();
716: while (iterator.hasNext()) {
717: Object next = iterator.next();
718: if (next instanceof SiteFeatureAdapter) {
719: if ((((SiteFeatureAdapter) next).feature) != null) {
720: features.add(((SiteFeatureAdapter) next).feature);
721: }
722: }
723: }
724: cachedFeatures = (ISiteFeature[]) features
725: .toArray(new ISiteFeature[features.size()]);
726: return cachedFeatures;
727: }
728:
729: /**
730: * Finds a feature with the same id and version as a site feature. If
731: * feature is not found, but feature with a M.m.s.qualifier exists it will
732: * be returned.
733: *
734: * @param siteFeature
735: * @return IFeature or null
736: */
737: public static IFeature findFeature(ISiteFeature siteFeature) {
738: IFeatureModel model = PDECore.getDefault()
739: .getFeatureModelManager().findFeatureModelRelaxed(
740: siteFeature.getId(), siteFeature.getVersion());
741: if (model != null)
742: return model.getFeature();
743: return null;
744: }
745:
746: private void handleImportEnvironment() {
747: IStructuredSelection sel = (IStructuredSelection) fCategoryViewer
748: .getSelection();
749: final ISiteFeature[] selectedFeatures = getFeaturesFromSelection(sel);
750: BusyIndicator.showWhile(fCategoryTreePart.getControl()
751: .getDisplay(), new Runnable() {
752: public void run() {
753: new SynchronizePropertiesAction(selectedFeatures,
754: getModel()).run();
755: }
756: });
757: }
758:
759: private void handleNewFeature() {
760: final Control control = fCategoryViewer.getControl();
761: BusyIndicator.showWhile(control.getDisplay(), new Runnable() {
762: public void run() {
763: IFeatureModel[] allModels = PDECore.getDefault()
764: .getFeatureModelManager().getModels();
765: ArrayList newModels = new ArrayList();
766: for (int i = 0; i < allModels.length; i++) {
767: if (canAdd(allModels[i]))
768: newModels.add(allModels[i]);
769: }
770: IFeatureModel[] candidateModels = (IFeatureModel[]) newModels
771: .toArray(new IFeatureModel[newModels.size()]);
772: FeatureSelectionDialog dialog = new FeatureSelectionDialog(
773: fCategoryViewer.getTree().getShell(),
774: candidateModels, true);
775: if (dialog.open() == Window.OK) {
776: Object[] models = dialog.getResult();
777: try {
778: doAdd(models);
779: } catch (CoreException e) {
780: PDEPlugin.log(e);
781: }
782: }
783: }
784: });
785: }
786:
787: private boolean canAdd(IFeatureModel candidate) {
788: ISiteFeature[] features = fModel.getSite().getFeatures();
789: IFeature cfeature = candidate.getFeature();
790:
791: for (int i = 0; i < features.length; i++) {
792: ISiteFeature bfeature = features[i];
793: if (bfeature.getId().equals(cfeature.getId())
794: && bfeature.getVersion().equals(
795: cfeature.getVersion()))
796: return false;
797: }
798: return true;
799: }
800:
801: public static ISiteFeature createSiteFeature(ISiteModel model,
802: IFeatureModel featureModel) throws CoreException {
803: IFeature feature = featureModel.getFeature();
804: ISiteFeature sfeature = model.getFactory().createFeature();
805: sfeature.setId(feature.getId());
806: sfeature.setVersion(feature.getVersion());
807: // sfeature.setURL(model.getBuildModel().getSiteBuild().getFeatureLocation()
808: // + "/" + feature.getId() + "_" + feature.getVersion() + ".jar");
809: // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
810: sfeature
811: .setURL("features/" + feature.getId() + "_" + formatVersion(feature.getVersion()) + ".jar"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
812: sfeature.setOS(feature.getOS());
813: sfeature.setWS(feature.getWS());
814: sfeature.setArch(feature.getArch());
815: sfeature.setNL(feature.getNL());
816: sfeature.setIsPatch(isFeaturePatch(feature));
817: return sfeature;
818: }
819:
820: private static String formatVersion(String version) {
821: try {
822: Version v = new Version(version);
823: return v.toString();
824: } catch (IllegalArgumentException e) {
825: }
826: return version;
827: }
828:
829: private static boolean isFeaturePatch(IFeature feature) {
830: IFeatureImport[] imports = feature.getImports();
831: for (int i = 0; i < imports.length; i++) {
832: if (imports[i].isPatch())
833: return true;
834: }
835: return false;
836: }
837:
838: public ISiteModel getModel() {
839: return fModel;
840: }
841:
842: /**
843: *
844: * @param candidates
845: * Array of IFeatureModel
846: * @param monitor
847: * @throws CoreException
848: */
849: public void doAdd(Object[] candidates) throws CoreException {
850: // Category to add features to
851: String categoryName = null;
852: ISelection selection = fCategoryViewer.getSelection();
853: if (!selection.isEmpty()
854: && selection instanceof IStructuredSelection) {
855: Object element = ((IStructuredSelection) selection)
856: .getFirstElement();
857: if (element instanceof ISiteCategoryDefinition) {
858: categoryName = ((ISiteCategoryDefinition) element)
859: .getName();
860: } else if (element instanceof SiteFeatureAdapter) {
861: categoryName = ((SiteFeatureAdapter) element).category;
862: }
863: }
864: //
865: ISiteFeature[] added = new ISiteFeature[candidates.length];
866: for (int i = 0; i < candidates.length; i++) {
867: IFeatureModel candidate = (IFeatureModel) candidates[i];
868: ISiteFeature child = createSiteFeature(fModel, candidate);
869: if (categoryName != null) {
870: addCategory(child, categoryName);
871: }
872: added[i] = child;
873: }
874:
875: // Update model
876: fModel.getSite().addFeatures(added);
877: // Select last added feature
878: if (added.length > 0) {
879: if (categoryName != null) {
880: expandCategory(categoryName);
881: }
882: fCategoryViewer.setSelection(new StructuredSelection(
883: new SiteFeatureAdapter(categoryName,
884: added[added.length - 1])), true);
885: }
886: }
887:
888: void fireSelection() {
889: fCategoryViewer.setSelection(fCategoryViewer.getSelection());
890: }
891:
892: /* (non-Javadoc)
893: * @see org.eclipse.ui.forms.AbstractFormPart#setFormInput(java.lang.Object)
894: */
895: public boolean setFormInput(Object input) {
896: if (input instanceof ISiteCategoryDefinition) {
897: fCategoryViewer.setSelection(
898: new StructuredSelection(input), true);
899: return true;
900: }
901: if (input instanceof SiteFeatureAdapter) {
902: // first, expand the category, otherwise tree will not find the feature
903: String category = ((SiteFeatureAdapter) input).category;
904: if (category != null) {
905: expandCategory(category);
906: }
907: fCategoryViewer.setSelection(
908: new StructuredSelection(input), true);
909: return true;
910: }
911: return super .setFormInput(input);
912: }
913:
914: private void expandCategory(String category) {
915: if (category != null) {
916: ISiteCategoryDefinition[] catDefs = fModel.getSite()
917: .getCategoryDefinitions();
918: for (int i = 0; i < catDefs.length; i++) {
919: if (category.equals(catDefs[i].getName())) {
920: fCategoryViewer.expandToLevel(catDefs[i], 1);
921: break;
922: }
923: }
924: }
925:
926: }
927:
928: public void modelsChanged(IFeatureModelDelta delta) {
929: markStale();
930: }
931: }
|