1 11 package org.eclipse.pde.internal.ui.editor.plugin; 12 import java.util.ArrayList ; 13 import java.util.Iterator ; 14 import java.util.Map ; 15 16 import org.eclipse.core.runtime.CoreException; 17 import org.eclipse.jface.action.IMenuManager; 18 import org.eclipse.jface.text.BadLocationException; 19 import org.eclipse.jface.text.ITextSelection; 20 import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; 21 import org.eclipse.jface.viewers.ILabelProvider; 22 import org.eclipse.jface.viewers.ISelection; 23 import org.eclipse.jface.viewers.ITreeContentProvider; 24 import org.eclipse.jface.viewers.LabelProvider; 25 import org.eclipse.jface.viewers.SelectionChangedEvent; 26 import org.eclipse.osgi.util.NLS; 27 import org.eclipse.pde.core.IBaseModel; 28 import org.eclipse.pde.core.plugin.IPluginLibrary; 29 import org.eclipse.pde.core.plugin.IPluginModelBase; 30 import org.eclipse.pde.internal.core.ibundle.IBundleModel; 31 import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase; 32 import org.eclipse.pde.internal.core.ibundle.IManifestHeader; 33 import org.eclipse.pde.internal.core.plugin.ImportObject; 34 import org.eclipse.pde.internal.core.text.AbstractEditingModel; 35 import org.eclipse.pde.internal.core.text.IDocumentKey; 36 import org.eclipse.pde.internal.core.text.IDocumentRange; 37 import org.eclipse.pde.internal.core.text.IEditingModel; 38 import org.eclipse.pde.internal.core.text.bundle.Bundle; 39 import org.eclipse.pde.internal.core.text.bundle.BundleClasspathHeader; 40 import org.eclipse.pde.internal.core.text.bundle.BundleModel; 41 import org.eclipse.pde.internal.core.text.bundle.BundleSymbolicNameHeader; 42 import org.eclipse.pde.internal.core.text.bundle.CompositeManifestHeader; 43 import org.eclipse.pde.internal.core.text.bundle.ExecutionEnvironment; 44 import org.eclipse.pde.internal.core.text.bundle.ExportPackageHeader; 45 import org.eclipse.pde.internal.core.text.bundle.ExportPackageObject; 46 import org.eclipse.pde.internal.core.text.bundle.ImportPackageHeader; 47 import org.eclipse.pde.internal.core.text.bundle.ImportPackageObject; 48 import org.eclipse.pde.internal.core.text.bundle.ManifestHeader; 49 import org.eclipse.pde.internal.core.text.bundle.PDEManifestElement; 50 import org.eclipse.pde.internal.core.text.bundle.PackageObject; 51 import org.eclipse.pde.internal.core.text.bundle.RequireBundleHeader; 52 import org.eclipse.pde.internal.core.text.bundle.RequireBundleObject; 53 import org.eclipse.pde.internal.core.text.bundle.RequiredExecutionEnvironmentHeader; 54 import org.eclipse.pde.internal.ui.PDELabelProvider; 55 import org.eclipse.pde.internal.ui.PDEPlugin; 56 import org.eclipse.pde.internal.ui.PDEPluginImages; 57 import org.eclipse.pde.internal.ui.PDEUIMessages; 58 import org.eclipse.pde.internal.ui.editor.KeyValueSourcePage; 59 import org.eclipse.pde.internal.ui.editor.PDEFormEditor; 60 import org.eclipse.pde.internal.ui.editor.actions.PDEActionConstants; 61 import org.eclipse.pde.internal.ui.elements.DefaultContentProvider; 62 import org.eclipse.pde.internal.ui.refactoring.RenamePluginAction; 63 import org.eclipse.pde.internal.ui.util.SharedLabelProvider; 64 import org.eclipse.swt.custom.StyledText; 65 import org.eclipse.swt.graphics.Image; 66 import org.eclipse.swt.graphics.Point; 67 import org.eclipse.ui.forms.editor.FormEditor; 68 import org.osgi.framework.Constants; 69 70 public class BundleSourcePage extends KeyValueSourcePage { 71 72 78 private Object fTargetOutlineSelection; 79 80 87 private int fCurrentHighlightRangeOffset; 88 89 private final int F_NOT_SET = -1; 90 91 private RenamePluginAction fRenameAction; 92 93 97 private class BundleOutlineContentProvider extends DefaultContentProvider 98 implements ITreeContentProvider { 99 100 public Object [] getChildren(Object parent) { 101 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).getEnvironments(); 108 } else if (parent instanceof RequireBundleHeader) { 109 return ((RequireBundleHeader)parent).getRequiredBundles(); 110 } else if (parent instanceof BundleClasspathHeader) { 111 return getPluginLibraries(); 112 } 113 return new Object [0]; 114 } 115 116 private Object [] getPluginLibraries() { 117 IPluginLibrary[] libraries = getBundleClasspathLibraries(); 118 if ((libraries == null) || 119 (libraries.length == 0)) { 120 return new Object [0]; 121 } 122 return libraries; 123 } 124 125 public boolean hasChildren(Object parent) { 126 return getChildren(parent).length > 0; 127 } 128 public Object getParent(Object child) { 129 return null; 130 } 131 public Object [] getElements(Object parent) { 132 if (parent instanceof BundleModel) { 133 BundleModel model = (BundleModel) parent; 134 Map manifest = ((Bundle)model.getBundle()).getHeaders(); 135 ArrayList keys = new ArrayList (); 136 for (Iterator elements = manifest.keySet().iterator(); elements.hasNext();) { 137 IDocumentKey key = (IDocumentKey) manifest.get(elements.next()); 138 if (key.getOffset() > -1) 139 keys.add(key); 140 } 141 return keys.toArray(); 142 } 143 return new Object [0]; 144 } 145 } 146 147 150 private IPluginLibrary[] getBundleClasspathLibraries() { 151 FormEditor editor = getEditor(); 154 if (editor instanceof PDEFormEditor) { 155 PDEFormEditor formEditor = (PDEFormEditor)editor; 156 IBaseModel baseModel = formEditor.getAggregateModel(); 157 if (baseModel instanceof IPluginModelBase) { 158 IPluginLibrary[] libraries = 159 ((IPluginModelBase)baseModel).getPluginBase().getLibraries(); 160 return libraries; 161 } 162 } 163 return null; 164 } 165 166 private class BundleLabelProvider extends LabelProvider { 167 public String getText(Object obj) { 169 if (obj instanceof PackageObject) { 170 return ((PackageObject)obj).getName(); 171 } else if (obj instanceof ExecutionEnvironment) { 172 return ((ExecutionEnvironment)obj).getName(); 173 } else if (obj instanceof RequireBundleObject) { 174 return getTextRequireBundle(((RequireBundleObject)obj)); 175 } else if (obj instanceof ManifestHeader) { 176 return ((ManifestHeader) obj).getName(); 177 } 178 return super.getText(obj); 179 } 180 181 private String getTextRequireBundle(RequireBundleObject bundle) { 182 StringBuffer label = new StringBuffer (); 183 label.append(bundle.getId()); 185 String version = bundle.getVersion(); 187 if ((version == null) || 189 (version.length() == 0)) { 190 return label.toString(); 191 } 192 label.append(' '); 194 char firstChar = version.charAt(0); 198 if ((firstChar != '(') && 199 (firstChar != '[')) { 200 label.append('('); 201 } 202 label.append(version); 204 char lastChar = version.charAt(version.length() - 1); 208 if ((lastChar != ')') && 209 (lastChar != ']')) { 210 label.append(')'); 211 } 212 return label.toString(); 214 } 215 216 public Image getImage(Object obj) { 217 PDELabelProvider labelProvider = 218 PDEPlugin.getDefault().getLabelProvider(); 219 if (obj instanceof PackageObject) { 220 return labelProvider.get( 221 PDEPluginImages.DESC_PACKAGE_OBJ); 222 } else if (obj instanceof ExecutionEnvironment) { 223 return labelProvider.get( 224 PDEPluginImages.DESC_JAVA_LIB_OBJ); 225 } else if (obj instanceof RequireBundleObject) { 226 int flags = SharedLabelProvider.F_EXTERNAL; 227 if (((RequireBundleObject)obj).isReexported()) { 228 flags = flags | SharedLabelProvider.F_EXPORT; 229 } 230 return labelProvider.get(PDEPluginImages.DESC_REQ_PLUGIN_OBJ, flags); 231 } else if (obj instanceof ManifestHeader) { 232 return labelProvider.get( 233 PDEPluginImages.DESC_BUILD_VAR_OBJ); 234 } else if (obj instanceof IPluginLibrary) { 235 return labelProvider.get( 236 PDEPluginImages.DESC_JAVA_LIB_OBJ); 237 } 238 return null; 239 } 240 } 241 242 247 public BundleSourcePage(PDEFormEditor editor, String id, String title) { 248 super(editor, id, title); 249 resetTargetOutlineSelection(); 250 resetCurrentHighlightRangeOffset(); 251 } 252 253 256 private void setCurrentHighlightRangeOffset(int offset) { 257 fCurrentHighlightRangeOffset = offset; 258 } 259 260 263 private void resetCurrentHighlightRangeOffset() { 264 fCurrentHighlightRangeOffset = F_NOT_SET; 265 } 266 267 270 private int getCurrentHighlightRangeOffset() { 271 return fCurrentHighlightRangeOffset; 272 } 273 274 277 public void resetHighlightRange() { 278 resetCurrentHighlightRangeOffset(); 279 super.resetHighlightRange(); 280 } 281 282 285 private void resetTargetOutlineSelection() { 286 fTargetOutlineSelection = null; 287 } 288 289 292 private void setTargetOutlineSelection(Object object) { 293 fTargetOutlineSelection = object; 294 } 295 296 299 private Object getTargetOutlineSelection() { 300 return fTargetOutlineSelection; 301 } 302 303 public ILabelProvider createOutlineLabelProvider() { 304 return new BundleLabelProvider(); 305 } 306 307 public ITreeContentProvider createOutlineContentProvider() { 308 return new BundleOutlineContentProvider(); 309 } 310 311 314 public IDocumentRange getRangeElement(int offset, boolean searchChildren) { 315 IBundleModel model = (IBundleModel) getInputContext().getModel(); 316 Map manifest = ((Bundle) model.getBundle()).getHeaders(); 317 resetTargetOutlineSelection(); 319 for (Iterator elements = manifest.values().iterator(); elements.hasNext();) { 321 IDocumentRange node = (IDocumentRange) elements.next(); 322 if (isWithinCurrentRange(offset, node)) { 324 if (searchChildren && 327 (node instanceof CompositeManifestHeader)) { 328 IDocumentRange child_node = getRangeElementChild(model, offset, 329 (CompositeManifestHeader)node); 330 if (child_node != null) { 333 return child_node; 334 } 335 } 336 setTargetOutlineSelection(node); 339 return node; 340 } 341 } 342 return null; 343 } 344 345 350 private boolean isWithinCurrentRange(int offset, IDocumentRange range) { 351 352 if (range == null) { 353 return false; 355 } else if (offset >= range.getOffset() 356 && (offset <= (range.getOffset() + range.getLength()))) { 357 return true; 359 } 360 return false; 362 } 363 364 373 private boolean isWithinPreviousRange(int offset, 374 IDocumentRange current_range, IDocumentRange previous_range) { 375 376 if ((current_range == null) || 377 (previous_range == null)) { 378 return false; 380 } else if ((offset >= previous_range.getOffset() + previous_range.getLength()) && 381 ((offset <= current_range.getOffset()))) { 382 return true; 384 } 385 return false; 387 } 388 389 394 private boolean isBeforePreviousRange(int offset, 395 IDocumentRange previousRange) { 396 397 if (previousRange == null) { 398 return false; 399 } else if (offset < previousRange.getOffset()) { 400 return true; 401 } 402 return false; 403 } 404 405 411 private IDocumentRange getRangeElementChild(IBundleModel model, 412 int offset, CompositeManifestHeader header) { 413 if (header.isEmpty()) { 415 return null; 416 } 417 PDEManifestElement[] elements = header.getElements(); 419 String headerName = getHeaderName(elements[0]); 422 PDEManifestElement previousElement = null; 423 PDEManifestElement currentElement = null; 424 IDocumentRange previousRange = null; 425 IDocumentRange currentRange = null; 426 for (int i = 0; i < elements.length; i++) { 428 currentElement = elements[i]; 429 currentRange = getSpecificRange( 431 model, 432 headerName, 433 currentElement.getValue()); 434 if (isBeforePreviousRange(offset, previousRange)) { 436 return null; 437 } else if (isWithinCurrentRange(offset, currentRange)) { 438 setChildTargetOutlineSelection(headerName, currentElement); 439 return currentRange; 441 } else if (isWithinPreviousRange(offset, currentRange, previousRange)) { 442 setChildTargetOutlineSelection(headerName, previousElement); 443 return previousRange; 445 } 446 previousRange = currentRange; 448 previousElement = currentElement; 449 } 450 451 if (isWithinLastElementParamRange(offset, currentRange, header)) { 452 setChildTargetOutlineSelection(headerName, currentElement); 454 return currentRange; 456 } 457 return null; 458 } 459 460 461 467 private boolean isWithinLastElementParamRange(int offset, 468 IDocumentRange currentRange, IDocumentRange headerRange) { 469 if (currentRange == null) { 470 return false; 471 } else if ((offset >= currentRange.getOffset() + currentRange.getLength()) && 472 (offset <= (headerRange.getOffset() + headerRange.getLength()))) { 473 return true; 474 } 475 return false; 476 } 477 478 482 private void setChildTargetOutlineSelection(String headerName, 483 PDEManifestElement element) { 484 if (headerName.equalsIgnoreCase(Constants.BUNDLE_CLASSPATH)) { 486 setTargetOutlineSelection( 487 getBundleClasspathOutlineSelection(element)); 488 } else { 489 setTargetOutlineSelection(element); 490 } 491 } 492 493 500 private Object getBundleClasspathOutlineSelection( 501 PDEManifestElement manifestElement) { 502 503 IPluginLibrary[] libraries = getBundleClasspathLibraries(); 504 if ((libraries == null) || 506 (libraries.length == 0)) { 507 return null; 508 } 509 for (int i = 0; i < libraries.length; i++) { 511 if (manifestElement.getValue().equals(libraries[i].getName())) { 512 return libraries[i]; 514 } 515 } 516 return null; 518 } 519 520 524 private String getHeaderName(PDEManifestElement element) { 525 if (element instanceof ExportPackageObject) { 526 return Constants.EXPORT_PACKAGE; 527 } else if (element instanceof ImportPackageObject) { 528 return Constants.IMPORT_PACKAGE; 529 } else if (element instanceof ExecutionEnvironment) { 530 return Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT; 531 } else if (element instanceof RequireBundleObject) { 532 return Constants.REQUIRE_BUNDLE; 533 } else { 534 return Constants.BUNDLE_CLASSPATH; 540 } 541 } 542 543 protected String [] collectContextMenuPreferencePages() { 544 String [] ids= super.collectContextMenuPreferencePages(); 545 String [] more= new String [ids.length + 1]; 546 more[0]= "org.eclipse.pde.ui.EditorPreferencePage"; System.arraycopy(ids, 0, more, 1, ids.length); 548 return more; 549 } 550 551 public IDocumentRange findRange() { 552 if (fSelection instanceof ImportObject) { 553 IPluginModelBase base = ((ImportObject)fSelection).getImport().getPluginModel(); 554 if (base instanceof IBundlePluginModelBase) 555 return getSpecificRange( 556 ((IBundlePluginModelBase)base).getBundleModel(), 557 Constants.REQUIRE_BUNDLE, 558 ((ImportObject)fSelection).getId()); 559 } else if (fSelection instanceof ImportPackageObject) { 560 return getSpecificRange( 561 ((ImportPackageObject)fSelection).getModel(), 562 Constants.IMPORT_PACKAGE, 563 ((ImportPackageObject)fSelection).getValue()); 564 } else if (fSelection instanceof ExportPackageObject) { 565 return getSpecificRange( 566 ((ExportPackageObject)fSelection).getModel(), 567 Constants.EXPORT_PACKAGE, 568 ((ExportPackageObject)fSelection).getValue()); 569 } else if (fSelection instanceof IPluginLibrary) { 570 IPluginModelBase base = ((IPluginLibrary)fSelection).getPluginModel(); 571 if (base instanceof IBundlePluginModelBase) 572 return getSpecificRange( 573 ((IBundlePluginModelBase)base).getBundleModel(), 574 Constants.BUNDLE_CLASSPATH, 575 ((IPluginLibrary)fSelection).getName()); 576 } else if (fSelection instanceof ExecutionEnvironment) { 577 return getSpecificRange( 578 ((ExecutionEnvironment)fSelection).getModel(), 579 Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, 580 ((ExecutionEnvironment)fSelection).getValue()); 581 } else if (fSelection instanceof RequireBundleObject) { 582 return getSpecificRange( 583 ((RequireBundleObject)fSelection).getModel(), 584 Constants.REQUIRE_BUNDLE, 585 ((RequireBundleObject)fSelection).getId()); 586 } 587 return null; 588 } 589 590 public static IDocumentRange getSpecificRange(IBundleModel model, IManifestHeader header, String element) { 591 if (header == null || !(model instanceof IEditingModel)) 592 return null; 593 594 final int[] range = new int[] { -1, -1 }; try { 596 int start = header.getOffset() + header.getName().length(); 597 int length = header.getLength() - header.getName().length(); 598 String headerValue = ((IEditingModel)model).getDocument().get(start, length); 599 600 int i = headerValue.indexOf(element); 601 int last = headerValue.lastIndexOf(element); 602 if (i > 0 && i != last) { 603 char[] sChar = element.toCharArray(); 604 char[] headerChar = headerValue.toCharArray(); 605 headLoop: for (; i <= last; i++) { 606 if (headerChar[i] != sChar[0] && 608 headerChar[i + sChar.length / 2] != sChar[sChar.length / 2] && 609 headerChar[i + sChar.length - 1] != sChar[sChar.length - 1]) 610 continue headLoop; 611 612 for (int j = 1; j < sChar.length - 1; j++) 613 if (headerChar[i + j] != sChar[j]) 614 continue headLoop; 615 616 char c = headerChar[i - 1]; 618 if (!Character.isWhitespace(c) && c != ',') 619 continue headLoop; 621 622 int index = i + sChar.length; 623 if (index >= headerChar.length) { 624 continue; 627 } 628 c = headerChar[index]; 629 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '.') 630 continue headLoop; 632 633 break; 634 } 635 } 636 if (i != -1) { 637 range[0] = start + i; 638 range[1] = element.length(); 639 } 640 } catch (BadLocationException e) { 641 } 642 if (range[0] == -1) { range[0] = header.getOffset(); 644 range[1] = header.getName().length(); 647 } 648 return new IDocumentRange() { 649 public int getOffset() { return range[0]; } 650 public int getLength() { return range[1]; } 651 }; 652 } 653 654 public static IDocumentRange getSpecificRange(IBundleModel model, String headerName, String search) { 655 IManifestHeader header = model.getBundle().getManifestHeader(headerName); 656 return getSpecificRange(model, header, search); 657 } 658 659 protected boolean isSelectionListener() { 660 return true; 661 } 662 663 public Object getAdapter(Class adapter) { 664 if (IHyperlinkDetector.class.equals(adapter)) 665 return new BundleHyperlinkDetector(this); 666 return super.getAdapter(adapter); 667 } 668 669 672 public void updateSelection(Object object) { 673 fSelection = object; 675 if (object instanceof IDocumentKey) { 677 setHighlightRange((IDocumentKey)object); 678 setCurrentHighlightRangeOffset(((IDocumentKey)object).getOffset()); 679 return; 682 } 683 IDocumentRange range = findRange(); 686 if (range == null) { 688 return; 689 } 690 IBaseModel model = getInputContext().getModel(); 692 if ((model instanceof AbstractEditingModel) == false) { 694 return; 695 } 696 if ((range.getOffset() == -1) || 699 isDirty()) { 700 try { 701 ((AbstractEditingModel)model).adjustOffsets( 702 ((AbstractEditingModel)model).getDocument()); 703 } catch (CoreException e) { 704 } 706 range = findRange(); 707 } 708 setCurrentHighlightRangeOffset(range.getOffset()); 710 setHighlightRange(range, true); 711 setSelectedRange(range, false); 712 } 713 714 717 protected void handleSelectionChangedSourcePage(SelectionChangedEvent event) { 718 ISelection selection = event.getSelection(); 719 if (selection.isEmpty() || 721 ((selection instanceof ITextSelection) == false)) { 722 return; 723 } 724 IBaseModel model = getInputContext().getModel(); 727 if (model instanceof AbstractEditingModel 728 && isDirty()) { 729 try { 730 ((AbstractEditingModel)model).adjustOffsets( 731 ((AbstractEditingModel)model).getDocument()); 732 } catch (CoreException e) { 733 } 735 } 736 synchronizeOutlinePage(((ITextSelection) selection).getOffset()); 738 } 739 740 743 protected void synchronizeOutlinePage(int offset) { 744 int previous_offset = getCurrentHighlightRangeOffset(); 749 if (previous_offset == offset) { 750 return; 751 } 752 IDocumentRange rangeElement = 755 getRangeElement(offset, true); 756 updateHighlightRange(rangeElement); 758 updateOutlinePageSelection(getTargetOutlineSelection()); 760 } 761 762 protected void editorContextMenuAboutToShow(IMenuManager menu) { 763 super.editorContextMenuAboutToShow(menu); 764 StyledText text = getViewer().getTextWidget(); 765 Point p = text.getSelection(); 766 IDocumentRange element = getRangeElement(p.x, false); 767 if (!(element instanceof BundleSymbolicNameHeader) || !(((BundleSymbolicNameHeader)element).getModel().isEditable())) 769 return; 770 if (fRenameAction == null) { 771 IBaseModel base = ((PDEFormEditor)getEditor()).getAggregateModel(); 772 if (base instanceof IPluginModelBase) { 773 fRenameAction = new RenamePluginAction(); 774 fRenameAction.setText(NLS.bind(PDEUIMessages.BundleSourcePage_renameActionText, Constants.BUNDLE_SYMBOLICNAME)); 775 fRenameAction.setPlugin((IPluginModelBase)base); 776 } 777 } 778 if (fRenameAction != null) 779 menu.insertAfter(PDEActionConstants.COMMAND_ID_QUICK_OUTLINE, fRenameAction); 781 } 782 783 786 public void setActive(boolean active) { 787 super.setActive(active); 788 if (active) { 790 updateTextSelection(); 791 } 792 } 793 794 } 795 | Popular Tags |