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: *******************************************************************************/package org.eclipse.pde.internal.ui.editor.plugin;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.Map;
015:
016: import org.eclipse.core.runtime.CoreException;
017: import org.eclipse.jface.action.IMenuManager;
018: import org.eclipse.jface.text.BadLocationException;
019: import org.eclipse.jface.text.ITextSelection;
020: import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
021: import org.eclipse.jface.viewers.ILabelProvider;
022: import org.eclipse.jface.viewers.ISelection;
023: import org.eclipse.jface.viewers.ITreeContentProvider;
024: import org.eclipse.jface.viewers.LabelProvider;
025: import org.eclipse.jface.viewers.SelectionChangedEvent;
026: import org.eclipse.osgi.util.NLS;
027: import org.eclipse.pde.core.IBaseModel;
028: import org.eclipse.pde.core.plugin.IPluginLibrary;
029: import org.eclipse.pde.core.plugin.IPluginModelBase;
030: import org.eclipse.pde.internal.core.ibundle.IBundleModel;
031: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
032: import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
033: import org.eclipse.pde.internal.core.plugin.ImportObject;
034: import org.eclipse.pde.internal.core.text.AbstractEditingModel;
035: import org.eclipse.pde.internal.core.text.IDocumentKey;
036: import org.eclipse.pde.internal.core.text.IDocumentRange;
037: import org.eclipse.pde.internal.core.text.IEditingModel;
038: import org.eclipse.pde.internal.core.text.bundle.Bundle;
039: import org.eclipse.pde.internal.core.text.bundle.BundleClasspathHeader;
040: import org.eclipse.pde.internal.core.text.bundle.BundleModel;
041: import org.eclipse.pde.internal.core.text.bundle.BundleSymbolicNameHeader;
042: import org.eclipse.pde.internal.core.text.bundle.CompositeManifestHeader;
043: import org.eclipse.pde.internal.core.text.bundle.ExecutionEnvironment;
044: import org.eclipse.pde.internal.core.text.bundle.ExportPackageHeader;
045: import org.eclipse.pde.internal.core.text.bundle.ExportPackageObject;
046: import org.eclipse.pde.internal.core.text.bundle.ImportPackageHeader;
047: import org.eclipse.pde.internal.core.text.bundle.ImportPackageObject;
048: import org.eclipse.pde.internal.core.text.bundle.ManifestHeader;
049: import org.eclipse.pde.internal.core.text.bundle.PDEManifestElement;
050: import org.eclipse.pde.internal.core.text.bundle.PackageObject;
051: import org.eclipse.pde.internal.core.text.bundle.RequireBundleHeader;
052: import org.eclipse.pde.internal.core.text.bundle.RequireBundleObject;
053: import org.eclipse.pde.internal.core.text.bundle.RequiredExecutionEnvironmentHeader;
054: import org.eclipse.pde.internal.ui.PDELabelProvider;
055: import org.eclipse.pde.internal.ui.PDEPlugin;
056: import org.eclipse.pde.internal.ui.PDEPluginImages;
057: import org.eclipse.pde.internal.ui.PDEUIMessages;
058: import org.eclipse.pde.internal.ui.editor.KeyValueSourcePage;
059: import org.eclipse.pde.internal.ui.editor.PDEFormEditor;
060: import org.eclipse.pde.internal.ui.editor.actions.PDEActionConstants;
061: import org.eclipse.pde.internal.ui.elements.DefaultContentProvider;
062: import org.eclipse.pde.internal.ui.refactoring.RenamePluginAction;
063: import org.eclipse.pde.internal.ui.util.SharedLabelProvider;
064: import org.eclipse.swt.custom.StyledText;
065: import org.eclipse.swt.graphics.Image;
066: import org.eclipse.swt.graphics.Point;
067: import org.eclipse.ui.forms.editor.FormEditor;
068: import org.osgi.framework.Constants;
069:
070: public class BundleSourcePage extends KeyValueSourcePage {
071:
072: /**
073: * Used to set the selection in the outline view with the link with editor
074: * feature is enabled
075: * Cannot use a document range object because manifest header elements
076: * do not have ranges associated with them in the bundle model
077: */
078: private Object fTargetOutlineSelection;
079:
080: /**
081: * Offset used to set the current highlight range.
082: * Used to prevent cyclic event firing when a selection is made in the
083: * outline view with the link with editor feature on. When a selection
084: * is made in the source viewer, an event is fired back to the outline
085: * view to unnecessarily update the selection.
086: */
087: private int fCurrentHighlightRangeOffset;
088:
089: private final int F_NOT_SET = -1;
090:
091: private RenamePluginAction fRenameAction;
092:
093: /**
094: * BundleOutlineContentProvider
095: *
096: */
097: private class BundleOutlineContentProvider extends
098: DefaultContentProvider implements ITreeContentProvider {
099:
100: public Object[] getChildren(Object parent) {
101: // Need an identifying class for label provider
102: if (parent instanceof ImportPackageHeader) {
103: return ((ImportPackageHeader) parent).getPackages();
104: } else if (parent instanceof ExportPackageHeader) {
105: return ((ExportPackageHeader) parent).getPackages();
106: } else if (parent instanceof RequiredExecutionEnvironmentHeader) {
107: return ((RequiredExecutionEnvironmentHeader) parent)
108: .getEnvironments();
109: } else if (parent instanceof RequireBundleHeader) {
110: return ((RequireBundleHeader) parent)
111: .getRequiredBundles();
112: } else if (parent instanceof BundleClasspathHeader) {
113: return getPluginLibraries();
114: }
115: return new Object[0];
116: }
117:
118: private Object[] getPluginLibraries() {
119: IPluginLibrary[] libraries = getBundleClasspathLibraries();
120: if ((libraries == null) || (libraries.length == 0)) {
121: return new Object[0];
122: }
123: return libraries;
124: }
125:
126: public boolean hasChildren(Object parent) {
127: return getChildren(parent).length > 0;
128: }
129:
130: public Object getParent(Object child) {
131: return null;
132: }
133:
134: public Object[] getElements(Object parent) {
135: if (parent instanceof BundleModel) {
136: BundleModel model = (BundleModel) parent;
137: Map manifest = ((Bundle) model.getBundle())
138: .getHeaders();
139: ArrayList keys = new ArrayList();
140: for (Iterator elements = manifest.keySet().iterator(); elements
141: .hasNext();) {
142: IDocumentKey key = (IDocumentKey) manifest
143: .get(elements.next());
144: if (key.getOffset() > -1)
145: keys.add(key);
146: }
147: return keys.toArray();
148: }
149: return new Object[0];
150: }
151: }
152:
153: /**
154: * @return
155: */
156: private IPluginLibrary[] getBundleClasspathLibraries() {
157: // The bundle classpath header has no model data members
158: // Retrieve the plug-in library equivalents from the editor model
159: FormEditor editor = getEditor();
160: if (editor instanceof PDEFormEditor) {
161: PDEFormEditor formEditor = (PDEFormEditor) editor;
162: IBaseModel baseModel = formEditor.getAggregateModel();
163: if (baseModel instanceof IPluginModelBase) {
164: IPluginLibrary[] libraries = ((IPluginModelBase) baseModel)
165: .getPluginBase().getLibraries();
166: return libraries;
167: }
168: }
169: return null;
170: }
171:
172: private class BundleLabelProvider extends LabelProvider {
173: // TODO: MP: QO: LOW: Move to PDELabelProvider
174: public String getText(Object obj) {
175: if (obj instanceof PackageObject) {
176: return ((PackageObject) obj).getName();
177: } else if (obj instanceof ExecutionEnvironment) {
178: return ((ExecutionEnvironment) obj).getName();
179: } else if (obj instanceof RequireBundleObject) {
180: return getTextRequireBundle(((RequireBundleObject) obj));
181: } else if (obj instanceof ManifestHeader) {
182: return ((ManifestHeader) obj).getName();
183: }
184: return super .getText(obj);
185: }
186:
187: private String getTextRequireBundle(RequireBundleObject bundle) {
188: StringBuffer label = new StringBuffer();
189: // Append the ID
190: label.append(bundle.getId());
191: // Get the version
192: String version = bundle.getVersion();
193: // If there is no version, just return what we have
194: if ((version == null) || (version.length() == 0)) {
195: return label.toString();
196: }
197: // Append a space
198: label.append(' ');
199: // If the first character does not have a range indicator,
200: // add a default one. This can happen when there is only one
201: // value specified for either min or max
202: char firstChar = version.charAt(0);
203: if ((firstChar != '(') && (firstChar != '[')) {
204: label.append('(');
205: }
206: // Append the version
207: label.append(version);
208: // If the last character does not have a range indicator,
209: // add a default one. This can happen when there is only one
210: // value specified for either min or max
211: char lastChar = version.charAt(version.length() - 1);
212: if ((lastChar != ')') && (lastChar != ']')) {
213: label.append(')');
214: }
215: // Return what we have
216: return label.toString();
217: }
218:
219: public Image getImage(Object obj) {
220: PDELabelProvider labelProvider = PDEPlugin.getDefault()
221: .getLabelProvider();
222: if (obj instanceof PackageObject) {
223: return labelProvider
224: .get(PDEPluginImages.DESC_PACKAGE_OBJ);
225: } else if (obj instanceof ExecutionEnvironment) {
226: return labelProvider
227: .get(PDEPluginImages.DESC_JAVA_LIB_OBJ);
228: } else if (obj instanceof RequireBundleObject) {
229: int flags = SharedLabelProvider.F_EXTERNAL;
230: if (((RequireBundleObject) obj).isReexported()) {
231: flags = flags | SharedLabelProvider.F_EXPORT;
232: }
233: return labelProvider.get(
234: PDEPluginImages.DESC_REQ_PLUGIN_OBJ, flags);
235: } else if (obj instanceof ManifestHeader) {
236: return labelProvider
237: .get(PDEPluginImages.DESC_BUILD_VAR_OBJ);
238: } else if (obj instanceof IPluginLibrary) {
239: return labelProvider
240: .get(PDEPluginImages.DESC_JAVA_LIB_OBJ);
241: }
242: return null;
243: }
244: }
245:
246: /**
247: * @param editor
248: * @param id
249: * @param title
250: */
251: public BundleSourcePage(PDEFormEditor editor, String id,
252: String title) {
253: super (editor, id, title);
254: resetTargetOutlineSelection();
255: resetCurrentHighlightRangeOffset();
256: }
257:
258: /**
259: * @param offset
260: */
261: private void setCurrentHighlightRangeOffset(int offset) {
262: fCurrentHighlightRangeOffset = offset;
263: }
264:
265: /**
266: *
267: */
268: private void resetCurrentHighlightRangeOffset() {
269: fCurrentHighlightRangeOffset = F_NOT_SET;
270: }
271:
272: /**
273: * @return
274: */
275: private int getCurrentHighlightRangeOffset() {
276: return fCurrentHighlightRangeOffset;
277: }
278:
279: /* (non-Javadoc)
280: * @see org.eclipse.ui.texteditor.AbstractTextEditor#resetHighlightRange()
281: */
282: public void resetHighlightRange() {
283: resetCurrentHighlightRangeOffset();
284: super .resetHighlightRange();
285: }
286:
287: /**
288: *
289: */
290: private void resetTargetOutlineSelection() {
291: fTargetOutlineSelection = null;
292: }
293:
294: /**
295: * @param object
296: */
297: private void setTargetOutlineSelection(Object object) {
298: fTargetOutlineSelection = object;
299: }
300:
301: /**
302: * @return
303: */
304: private Object getTargetOutlineSelection() {
305: return fTargetOutlineSelection;
306: }
307:
308: public ILabelProvider createOutlineLabelProvider() {
309: return new BundleLabelProvider();
310: }
311:
312: public ITreeContentProvider createOutlineContentProvider() {
313: return new BundleOutlineContentProvider();
314: }
315:
316: /* (non-Javadoc)
317: * @see org.eclipse.pde.internal.ui.editor.PDESourcePage#getRangeElement(int, boolean)
318: */
319: public IDocumentRange getRangeElement(int offset,
320: boolean searchChildren) {
321: IBundleModel model = (IBundleModel) getInputContext()
322: .getModel();
323: Map manifest = ((Bundle) model.getBundle()).getHeaders();
324: // Reset
325: resetTargetOutlineSelection();
326: // Search each manifest header
327: for (Iterator elements = manifest.values().iterator(); elements
328: .hasNext();) {
329: IDocumentRange node = (IDocumentRange) elements.next();
330: // Check to see if the parent is within range
331: if (isWithinCurrentRange(offset, node)) {
332: // Search the children of composite manifest headers first if
333: // specified
334: if (searchChildren
335: && (node instanceof CompositeManifestHeader)) {
336: IDocumentRange child_node = getRangeElementChild(
337: model, offset,
338: (CompositeManifestHeader) node);
339: // If the child node is specified return it; otherwise, we
340: // will default to the parent node
341: if (child_node != null) {
342: return child_node;
343: }
344: }
345: // A manifest header object can be used both for setting the
346: // highlight range and making a selection in the outline view
347: setTargetOutlineSelection(node);
348: return node;
349: }
350: }
351: return null;
352: }
353:
354: /**
355: * @param offset
356: * @param range
357: * @return true if the offset is within the range; false, otherwise
358: */
359: private boolean isWithinCurrentRange(int offset,
360: IDocumentRange range) {
361:
362: if (range == null) {
363: // Range not set
364: return false;
365: } else if (offset >= range.getOffset()
366: && (offset <= (range.getOffset() + range.getLength()))) {
367: // Offset within range
368: return true;
369: }
370: // Offset not within range
371: return false;
372: }
373:
374: /**
375: * This method is required because the calculated ranges, do NOT include
376: * their parameters (e.g. x-friends, bundle-version)
377: * @param offset
378: * @param current_range
379: * @param previous_range
380: * @return true if the offset falls in between the end of the previous range
381: * and before the current range (e.g. the previous ranges parameters)
382: */
383: private boolean isWithinPreviousRange(int offset,
384: IDocumentRange current_range, IDocumentRange previous_range) {
385:
386: if ((current_range == null) || (previous_range == null)) {
387: // Range not set
388: return false;
389: } else if ((offset >= previous_range.getOffset()
390: + previous_range.getLength())
391: && ((offset <= current_range.getOffset()))) {
392: // Offset within range
393: return true;
394: }
395: // Offset not within range
396: return false;
397: }
398:
399: /**
400: * @param offset
401: * @param previousRange
402: * @return
403: */
404: private boolean isBeforePreviousRange(int offset,
405: IDocumentRange previousRange) {
406:
407: if (previousRange == null) {
408: return false;
409: } else if (offset < previousRange.getOffset()) {
410: return true;
411: }
412: return false;
413: }
414:
415: /**
416: * @param model
417: * @param offset
418: * @param header
419: * @return
420: */
421: private IDocumentRange getRangeElementChild(IBundleModel model,
422: int offset, CompositeManifestHeader header) {
423: // Ensure the header has associated elements
424: if (header.isEmpty()) {
425: return null;
426: }
427: // Get the header elements
428: PDEManifestElement[] elements = header.getElements();
429: // Get the header elements name (assume that all elements are the same
430: // as the first element)
431: String headerName = getHeaderName(elements[0]);
432: PDEManifestElement previousElement = null;
433: PDEManifestElement currentElement = null;
434: IDocumentRange previousRange = null;
435: IDocumentRange currentRange = null;
436: // Process each element
437: for (int i = 0; i < elements.length; i++) {
438: currentElement = elements[i];
439: // Find the range for the element
440: currentRange = getSpecificRange(model, headerName,
441: currentElement.getValue());
442: // Determine whether the element is within range
443: if (isBeforePreviousRange(offset, previousRange)) {
444: return null;
445: } else if (isWithinCurrentRange(offset, currentRange)) {
446: setChildTargetOutlineSelection(headerName,
447: currentElement);
448: // Use for setting the highlight range
449: return currentRange;
450: } else if (isWithinPreviousRange(offset, currentRange,
451: previousRange)) {
452: setChildTargetOutlineSelection(headerName,
453: previousElement);
454: // Use for setting the highlight range
455: return previousRange;
456: }
457: // Update for the next iteration
458: previousRange = currentRange;
459: previousElement = currentElement;
460: }
461:
462: if (isWithinLastElementParamRange(offset, currentRange, header)) {
463: // No element found within range
464: setChildTargetOutlineSelection(headerName, currentElement);
465: // Use for setting the highlight range
466: return currentRange;
467: }
468: return null;
469: }
470:
471: /**
472: * @param offset
473: * @param currentRange
474: * @param headerRange
475: * @return
476: */
477: private boolean isWithinLastElementParamRange(int offset,
478: IDocumentRange currentRange, IDocumentRange headerRange) {
479: if (currentRange == null) {
480: return false;
481: } else if ((offset >= currentRange.getOffset()
482: + currentRange.getLength())
483: && (offset <= (headerRange.getOffset() + headerRange
484: .getLength()))) {
485: return true;
486: }
487: return false;
488: }
489:
490: /**
491: * @param headerName
492: * @param element
493: */
494: private void setChildTargetOutlineSelection(String headerName,
495: PDEManifestElement element) {
496: // Use for setting the outline view selection
497: if (headerName.equalsIgnoreCase(Constants.BUNDLE_CLASSPATH)) {
498: setTargetOutlineSelection(getBundleClasspathOutlineSelection(element));
499: } else {
500: setTargetOutlineSelection(element);
501: }
502: }
503:
504: /**
505: * Edge Case: Cannot use the PDEManifestElement directly to select bundle
506: * classpath elements in the outline view. Need to use IPluginLibrary
507: * objects
508: * @param manifestElement
509: * @return
510: */
511: private Object getBundleClasspathOutlineSelection(
512: PDEManifestElement manifestElement) {
513:
514: IPluginLibrary[] libraries = getBundleClasspathLibraries();
515: // Ensure there are libraries
516: if ((libraries == null) || (libraries.length == 0)) {
517: return null;
518: }
519: // Linearly search for the equivalent library object
520: for (int i = 0; i < libraries.length; i++) {
521: if (manifestElement.getValue().equals(
522: libraries[i].getName())) {
523: // Found
524: return libraries[i];
525: }
526: }
527: // None found
528: return null;
529: }
530:
531: /**
532: * @param element
533: * @return
534: */
535: private String getHeaderName(PDEManifestElement element) {
536: if (element instanceof ExportPackageObject) {
537: return Constants.EXPORT_PACKAGE;
538: } else if (element instanceof ImportPackageObject) {
539: return Constants.IMPORT_PACKAGE;
540: } else if (element instanceof ExecutionEnvironment) {
541: return Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT;
542: } else if (element instanceof RequireBundleObject) {
543: return Constants.REQUIRE_BUNDLE;
544: } else {
545: // Bundle classpath elements do not have their own model class
546: // They are created as PDEManifestElements directly whose value
547: // is just a String
548: // Assume that if the element is none of the above types it is this
549: // type
550: return Constants.BUNDLE_CLASSPATH;
551: }
552: }
553:
554: protected String[] collectContextMenuPreferencePages() {
555: String[] ids = super .collectContextMenuPreferencePages();
556: String[] more = new String[ids.length + 1];
557: more[0] = "org.eclipse.pde.ui.EditorPreferencePage"; //$NON-NLS-1$
558: System.arraycopy(ids, 0, more, 1, ids.length);
559: return more;
560: }
561:
562: public IDocumentRange findRange() {
563: if (fSelection instanceof ImportObject) {
564: IPluginModelBase base = ((ImportObject) fSelection)
565: .getImport().getPluginModel();
566: if (base instanceof IBundlePluginModelBase)
567: return getSpecificRange(((IBundlePluginModelBase) base)
568: .getBundleModel(), Constants.REQUIRE_BUNDLE,
569: ((ImportObject) fSelection).getId());
570: } else if (fSelection instanceof ImportPackageObject) {
571: return getSpecificRange(((ImportPackageObject) fSelection)
572: .getModel(), Constants.IMPORT_PACKAGE,
573: ((ImportPackageObject) fSelection).getValue());
574: } else if (fSelection instanceof ExportPackageObject) {
575: return getSpecificRange(((ExportPackageObject) fSelection)
576: .getModel(), Constants.EXPORT_PACKAGE,
577: ((ExportPackageObject) fSelection).getValue());
578: } else if (fSelection instanceof IPluginLibrary) {
579: IPluginModelBase base = ((IPluginLibrary) fSelection)
580: .getPluginModel();
581: if (base instanceof IBundlePluginModelBase)
582: return getSpecificRange(((IBundlePluginModelBase) base)
583: .getBundleModel(), Constants.BUNDLE_CLASSPATH,
584: ((IPluginLibrary) fSelection).getName());
585: } else if (fSelection instanceof ExecutionEnvironment) {
586: return getSpecificRange(((ExecutionEnvironment) fSelection)
587: .getModel(),
588: Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT,
589: ((ExecutionEnvironment) fSelection).getValue());
590: } else if (fSelection instanceof RequireBundleObject) {
591: return getSpecificRange(((RequireBundleObject) fSelection)
592: .getModel(), Constants.REQUIRE_BUNDLE,
593: ((RequireBundleObject) fSelection).getId());
594: }
595: return null;
596: }
597:
598: public static IDocumentRange getSpecificRange(IBundleModel model,
599: IManifestHeader header, String element) {
600: if (header == null || !(model instanceof IEditingModel))
601: return null;
602:
603: final int[] range = new int[] { -1, -1 }; // { offset, length }
604: try {
605: int start = header.getOffset() + header.getName().length();
606: int length = header.getLength() - header.getName().length();
607: String headerValue = ((IEditingModel) model).getDocument()
608: .get(start, length);
609:
610: int i = headerValue.indexOf(element);
611: int last = headerValue.lastIndexOf(element);
612: if (i > 0 && i != last) {
613: char[] sChar = element.toCharArray();
614: char[] headerChar = headerValue.toCharArray();
615: headLoop: for (; i <= last; i++) {
616: // check 1st, middle and last chars to speed things up
617: if (headerChar[i] != sChar[0]
618: && headerChar[i + sChar.length / 2] != sChar[sChar.length / 2]
619: && headerChar[i + sChar.length - 1] != sChar[sChar.length - 1])
620: continue headLoop;
621:
622: for (int j = 1; j < sChar.length - 1; j++)
623: if (headerChar[i + j] != sChar[j])
624: continue headLoop;
625:
626: // found match
627: char c = headerChar[i - 1];
628: if (!Character.isWhitespace(c) && c != ',')
629: // search string is contained by another
630: continue headLoop;
631:
632: int index = i + sChar.length;
633: if (index >= headerChar.length) {
634: // Current match is longer than search
635: // Occurs when match is '.' or a single character
636: continue;
637: }
638: c = headerChar[index];
639: if ((c >= 'a' && c <= 'z')
640: || (c >= 'A' && c <= 'Z') || c == '.')
641: // current match is longer than search
642: continue headLoop;
643:
644: break;
645: }
646: }
647: if (i != -1) {
648: range[0] = start + i;
649: range[1] = element.length();
650: }
651: } catch (BadLocationException e) {
652: }
653: if (range[0] == -1) { // if un-set offset use header range
654: range[0] = header.getOffset();
655: // Only select the length of the header name; otherwise, the
656: // header value will be included in the selection
657: range[1] = header.getName().length();
658: }
659: return new IDocumentRange() {
660: public int getOffset() {
661: return range[0];
662: }
663:
664: public int getLength() {
665: return range[1];
666: }
667: };
668: }
669:
670: public static IDocumentRange getSpecificRange(IBundleModel model,
671: String headerName, String search) {
672: IManifestHeader header = model.getBundle().getManifestHeader(
673: headerName);
674: return getSpecificRange(model, header, search);
675: }
676:
677: protected boolean isSelectionListener() {
678: return true;
679: }
680:
681: public Object getAdapter(Class adapter) {
682: if (IHyperlinkDetector.class.equals(adapter))
683: return new BundleHyperlinkDetector(this );
684: return super .getAdapter(adapter);
685: }
686:
687: /* (non-Javadoc)
688: * @see org.eclipse.pde.internal.ui.editor.PDESourcePage#updateSelection(java.lang.Object)
689: */
690: public void updateSelection(Object object) {
691: // Update the global selection
692: fSelection = object;
693: // Highlight the selection if it is a manifest header
694: if (object instanceof IDocumentKey) {
695: setHighlightRange((IDocumentKey) object);
696: setCurrentHighlightRangeOffset(((IDocumentKey) object)
697: .getOffset());
698: // We don't set the selected range because it will cause the
699: // manifest header and all its value to be selected
700: return;
701: }
702: // Handle manifest header values
703: // Determine the selection range
704: IDocumentRange range = findRange();
705: // Ensure there is a range
706: if (range == null) {
707: return;
708: }
709: // Get the model
710: IBaseModel model = getInputContext().getModel();
711: // Ensure we have an editing model
712: if ((model instanceof AbstractEditingModel) == false) {
713: return;
714: }
715: // If the range offset is undefined or the source viewer is dirty,
716: // forcibly adjust the offsets and try to find the range again
717: if ((range.getOffset() == -1) || isDirty()) {
718: try {
719: ((AbstractEditingModel) model)
720: .adjustOffsets(((AbstractEditingModel) model)
721: .getDocument());
722: } catch (CoreException e) {
723: // Ignore
724: }
725: range = findRange();
726: }
727: // Set the highlight and selected range with whatever we found
728: setCurrentHighlightRangeOffset(range.getOffset());
729: setHighlightRange(range, true);
730: setSelectedRange(range, false);
731: }
732:
733: /* (non-Javadoc)
734: * @see org.eclipse.pde.internal.ui.editor.PDESourcePage#handleSelectionChangedSourcePage(org.eclipse.jface.viewers.SelectionChangedEvent)
735: */
736: protected void handleSelectionChangedSourcePage(
737: SelectionChangedEvent event) {
738: ISelection selection = event.getSelection();
739: // Ensure we have a selection
740: if (selection.isEmpty()
741: || ((selection instanceof ITextSelection) == false)) {
742: return;
743: }
744: // If the page has been edited, adjust the offsets; otherwise, our
745: // caculated ranges will be out of sync
746: IBaseModel model = getInputContext().getModel();
747: if (model instanceof AbstractEditingModel && isDirty()) {
748: try {
749: ((AbstractEditingModel) model)
750: .adjustOffsets(((AbstractEditingModel) model)
751: .getDocument());
752: } catch (CoreException e) {
753: // Ignore
754: }
755: }
756: // Synchronize using the current cursor position in this page
757: synchronizeOutlinePage(((ITextSelection) selection).getOffset());
758: }
759:
760: /* (non-Javadoc)
761: * @see org.eclipse.pde.internal.ui.editor.PDESourcePage#synchronizeOutlinePage(int)
762: */
763: protected void synchronizeOutlinePage(int offset) {
764: // Prevent cyclical firing of events between source page and outline
765: // view
766: // If the previous offset is the same as the current offset, then
767: // the selection does not need to be updated in the outline view
768: int previous_offset = getCurrentHighlightRangeOffset();
769: if (previous_offset == offset) {
770: return;
771: }
772: // Find the range header (parent) or element (children) within range of
773: // the text selection offset
774: IDocumentRange rangeElement = getRangeElement(offset, true);
775: // Set the highlight range
776: updateHighlightRange(rangeElement);
777: // Set the outline view selection
778: updateOutlinePageSelection(getTargetOutlineSelection());
779: }
780:
781: protected void editorContextMenuAboutToShow(IMenuManager menu) {
782: super .editorContextMenuAboutToShow(menu);
783: StyledText text = getViewer().getTextWidget();
784: Point p = text.getSelection();
785: IDocumentRange element = getRangeElement(p.x, false);
786: // only activate rename when user is highlighting Bundle-SymbolicName header
787: if (!(element instanceof BundleSymbolicNameHeader)
788: || !(((BundleSymbolicNameHeader) element).getModel()
789: .isEditable()))
790: return;
791: if (fRenameAction == null) {
792: IBaseModel base = ((PDEFormEditor) getEditor())
793: .getAggregateModel();
794: if (base instanceof IPluginModelBase) {
795: fRenameAction = new RenamePluginAction();
796: fRenameAction
797: .setText(NLS
798: .bind(
799: PDEUIMessages.BundleSourcePage_renameActionText,
800: Constants.BUNDLE_SYMBOLICNAME));
801: fRenameAction.setPlugin((IPluginModelBase) base);
802: }
803: }
804: if (fRenameAction != null)
805: // add rename action after Outline. This is the same order as the hyperlink actions
806: menu.insertAfter(
807: PDEActionConstants.COMMAND_ID_QUICK_OUTLINE,
808: fRenameAction);
809: }
810:
811: /* (non-Javadoc)
812: * @see org.eclipse.pde.internal.ui.editor.PDESourcePage#setActive(boolean)
813: */
814: public void setActive(boolean active) {
815: super .setActive(active);
816: // Update the text selection if this page is being activated
817: if (active) {
818: updateTextSelection();
819: }
820: }
821:
822: }
|