0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2006 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.ui.internal.ide.dialogs;
0011:
0012: import java.io.IOException;
0013: import java.io.InputStream;
0014: import java.net.URL;
0015: import java.util.ArrayList;
0016: import java.util.Iterator;
0017:
0018: import javax.xml.parsers.ParserConfigurationException;
0019:
0020: import org.eclipse.core.resources.IMarker;
0021: import org.eclipse.core.runtime.IProgressMonitor;
0022: import org.eclipse.core.runtime.IStatus;
0023: import org.eclipse.core.runtime.Status;
0024: import org.eclipse.jface.action.MenuManager;
0025: import org.eclipse.jface.preference.JFacePreferences;
0026: import org.eclipse.jface.resource.JFaceColors;
0027: import org.eclipse.jface.resource.JFaceResources;
0028: import org.eclipse.jface.util.IPropertyChangeListener;
0029: import org.eclipse.jface.util.PropertyChangeEvent;
0030: import org.eclipse.swt.SWT;
0031: import org.eclipse.swt.custom.CLabel;
0032: import org.eclipse.swt.custom.ScrolledComposite;
0033: import org.eclipse.swt.custom.StyleRange;
0034: import org.eclipse.swt.custom.StyledText;
0035: import org.eclipse.swt.events.DisposeEvent;
0036: import org.eclipse.swt.events.DisposeListener;
0037: import org.eclipse.swt.events.FocusAdapter;
0038: import org.eclipse.swt.events.FocusEvent;
0039: import org.eclipse.swt.events.KeyEvent;
0040: import org.eclipse.swt.events.KeyListener;
0041: import org.eclipse.swt.events.MouseAdapter;
0042: import org.eclipse.swt.events.MouseEvent;
0043: import org.eclipse.swt.events.MouseMoveListener;
0044: import org.eclipse.swt.events.SelectionAdapter;
0045: import org.eclipse.swt.events.SelectionEvent;
0046: import org.eclipse.swt.events.TraverseEvent;
0047: import org.eclipse.swt.events.TraverseListener;
0048: import org.eclipse.swt.graphics.Color;
0049: import org.eclipse.swt.graphics.Cursor;
0050: import org.eclipse.swt.graphics.GC;
0051: import org.eclipse.swt.graphics.Point;
0052: import org.eclipse.swt.graphics.Rectangle;
0053: import org.eclipse.swt.layout.GridData;
0054: import org.eclipse.swt.layout.GridLayout;
0055: import org.eclipse.swt.widgets.Composite;
0056: import org.eclipse.swt.widgets.Display;
0057: import org.eclipse.swt.widgets.Event;
0058: import org.eclipse.swt.widgets.Label;
0059: import org.eclipse.swt.widgets.Listener;
0060: import org.eclipse.ui.IEditorInput;
0061: import org.eclipse.ui.IEditorSite;
0062: import org.eclipse.ui.PartInitException;
0063: import org.eclipse.ui.PlatformUI;
0064: import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
0065: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
0066: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
0067: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
0068: import org.eclipse.ui.part.EditorPart;
0069: import org.xml.sax.SAXException;
0070:
0071: /**
0072: * A "fake" editor to show a welcome page
0073: * The contents of this page are supplied in the product configuration
0074: *
0075: * PRIVATE
0076: * This class is internal to the workbench and must not be called outside the workbench
0077: */
0078: public class WelcomeEditor extends EditorPart {
0079:
0080: private final static int HORZ_SCROLL_INCREMENT = 20;
0081:
0082: private final static int VERT_SCROLL_INCREMENT = 20;
0083:
0084: // width at which wrapping will stop and a horizontal scroll bar will be
0085: // introduced
0086: private final static int WRAP_MIN_WIDTH = 150;
0087:
0088: private Composite editorComposite;
0089:
0090: private Cursor handCursor;
0091:
0092: private Cursor busyCursor;
0093:
0094: private WelcomeParser parser;
0095:
0096: private ArrayList hyperlinkRanges = new ArrayList();
0097:
0098: private ArrayList texts = new ArrayList();
0099:
0100: private ScrolledComposite scrolledComposite;
0101:
0102: private IPropertyChangeListener colorListener;
0103:
0104: private boolean mouseDown = false;
0105:
0106: private boolean dragEvent = false;
0107:
0108: private StyledText firstText, lastText;
0109:
0110: private StyledText lastNavigatedText, currentText;
0111:
0112: private boolean nextTabAbortTraversal,
0113: previousTabAbortTraversal = false;
0114:
0115: private WelcomeEditorCopyAction copyAction;
0116:
0117: /**
0118: * Create a new instance of the welcome editor
0119: */
0120: public WelcomeEditor() {
0121: super ();
0122: setPartName(IDEWorkbenchMessages.WelcomeEditor_title);
0123: copyAction = new WelcomeEditorCopyAction(this );
0124: copyAction.setEnabled(false);
0125: }
0126:
0127: /**
0128: * Update the welcome page to start at the
0129: * beginning of the text.
0130: */
0131: private void focusOn(StyledText newText, int caretOffset) {
0132: if (newText == null) {
0133: return;
0134: }
0135: newText.setFocus();
0136: newText.setCaretOffset(caretOffset);
0137: scrolledComposite.setOrigin(0, newText.getLocation().y);
0138: }
0139:
0140: /**
0141: * Finds the next text
0142: */
0143: private StyledText nextText(StyledText text) {
0144: int index = 0;
0145: if (text == null) {
0146: return (StyledText) texts.get(0);
0147: } else {
0148: index = texts.indexOf(text);
0149: }
0150:
0151: //If we are not at the end....
0152: if (index < texts.size() - 1) {
0153: return (StyledText) texts.get(index + 1);
0154: } else {
0155: return (StyledText) texts.get(0);
0156: }
0157: }
0158:
0159: /**
0160: * Finds the previous text
0161: */
0162: private StyledText previousText(StyledText text) {
0163: int index = 0;
0164: if (text == null) {
0165: return (StyledText) texts.get(0);
0166: } else {
0167: index = texts.indexOf(text);
0168: }
0169:
0170: //If we are at the beginning....
0171: if (index == 0) {
0172: return (StyledText) texts.get(texts.size() - 1);
0173: } else {
0174: return (StyledText) texts.get(index - 1);
0175: }
0176: }
0177:
0178: /**
0179: * Returns the current text.
0180: */
0181: protected StyledText getCurrentText() {
0182: return currentText;
0183: }
0184:
0185: /**
0186: * Returns the copy action.
0187: */
0188: protected WelcomeEditorCopyAction getCopyAction() {
0189: return copyAction;
0190: }
0191:
0192: /**
0193: * Finds the next link after the current selection.
0194: */
0195: private StyleRange findNextLink(StyledText text) {
0196: if (text == null) {
0197: return null;
0198: }
0199:
0200: WelcomeItem item = (WelcomeItem) text.getData();
0201: StyleRange[] ranges = text.getStyleRanges();
0202: int currentSelectionEnd = text.getSelection().y;
0203:
0204: for (int i = 0; i < ranges.length; i++) {
0205: if (ranges[i].start >= currentSelectionEnd) {
0206: if (item.isLinkAt(ranges[i].start)) {
0207: return ranges[i];
0208: }
0209: }
0210: }
0211: return null;
0212: }
0213:
0214: /**
0215: * Finds the previous link before the current selection.
0216: */
0217: private StyleRange findPreviousLink(StyledText text) {
0218: if (text == null) {
0219: return null;
0220: }
0221:
0222: WelcomeItem item = (WelcomeItem) text.getData();
0223: StyleRange[] ranges = text.getStyleRanges();
0224: int currentSelectionStart = text.getSelection().x;
0225:
0226: for (int i = ranges.length - 1; i > -1; i--) {
0227: if ((ranges[i].start + ranges[i].length) < currentSelectionStart) {
0228: if (item.isLinkAt(ranges[i].start + ranges[i].length
0229: - 1)) {
0230: return ranges[i];
0231: }
0232: }
0233: }
0234: return null;
0235: }
0236:
0237: /**
0238: * Finds the current link of the current selection.
0239: */
0240: protected StyleRange getCurrentLink(StyledText text) {
0241: StyleRange[] ranges = text.getStyleRanges();
0242: int currentSelectionEnd = text.getSelection().y;
0243: int currentSelectionStart = text.getSelection().x;
0244:
0245: for (int i = 0; i < ranges.length; i++) {
0246: if ((currentSelectionStart >= ranges[i].start)
0247: && (currentSelectionEnd <= (ranges[i].start + ranges[i].length))) {
0248: return ranges[i];
0249: }
0250: }
0251: return null;
0252: }
0253:
0254: /**
0255: * Adds listeners to the given styled text
0256: */
0257: private void addListeners(StyledText styledText) {
0258: styledText.addMouseListener(new MouseAdapter() {
0259: public void mouseDown(MouseEvent e) {
0260: if (e.button != 1) {
0261: return;
0262: }
0263: mouseDown = true;
0264: }
0265:
0266: public void mouseUp(MouseEvent e) {
0267: mouseDown = false;
0268: StyledText text = (StyledText) e.widget;
0269: WelcomeItem item = (WelcomeItem) e.widget.getData();
0270: int offset = text.getCaretOffset();
0271: if (dragEvent) {
0272: dragEvent = false;
0273: if (item.isLinkAt(offset)) {
0274: text.setCursor(handCursor);
0275: }
0276: } else if (item.isLinkAt(offset)) {
0277: text.setCursor(busyCursor);
0278: if (e.button == 1) {
0279: item.triggerLinkAt(offset);
0280: StyleRange selectionRange = getCurrentLink(text);
0281: text.setSelectionRange(selectionRange.start,
0282: selectionRange.length);
0283: text.setCursor(null);
0284: }
0285: }
0286: }
0287: });
0288:
0289: styledText.addMouseMoveListener(new MouseMoveListener() {
0290: public void mouseMove(MouseEvent e) {
0291: // Do not change cursor on drag events
0292: if (mouseDown) {
0293: if (!dragEvent) {
0294: StyledText text = (StyledText) e.widget;
0295: text.setCursor(null);
0296: }
0297: dragEvent = true;
0298: return;
0299: }
0300: StyledText text = (StyledText) e.widget;
0301: WelcomeItem item = (WelcomeItem) e.widget.getData();
0302: int offset = -1;
0303: try {
0304: offset = text.getOffsetAtLocation(new Point(e.x,
0305: e.y));
0306: } catch (IllegalArgumentException ex) {
0307: // location is not over a character
0308: }
0309: if (offset == -1) {
0310: text.setCursor(null);
0311: } else if (item.isLinkAt(offset)) {
0312: text.setCursor(handCursor);
0313: } else {
0314: text.setCursor(null);
0315: }
0316: }
0317: });
0318:
0319: styledText.addTraverseListener(new TraverseListener() {
0320: public void keyTraversed(TraverseEvent e) {
0321: StyledText text = (StyledText) e.widget;
0322:
0323: switch (e.detail) {
0324: case SWT.TRAVERSE_ESCAPE:
0325: e.doit = true;
0326: break;
0327: case SWT.TRAVERSE_TAB_NEXT:
0328: // Handle Ctrl-Tab
0329: if ((e.stateMask & SWT.CTRL) != 0) {
0330: if (e.widget == lastText) {
0331: return;
0332: } else {
0333: e.doit = false;
0334: nextTabAbortTraversal = true;
0335: lastText.traverse(SWT.TRAVERSE_TAB_NEXT);
0336: return;
0337: }
0338: }
0339: if (nextTabAbortTraversal) {
0340: nextTabAbortTraversal = false;
0341: return;
0342: }
0343: // Find the next link in current widget, if applicable
0344: // Stop at top of widget
0345: StyleRange nextLink = findNextLink(text);
0346: if (nextLink == null) {
0347: // go to the next widget, focus at beginning
0348: StyledText nextText = nextText(text);
0349: nextText.setSelection(0);
0350: focusOn(nextText, 0);
0351: } else {
0352: // focusOn: allow none tab traversals to align
0353: focusOn(text, text.getSelection().x);
0354: text.setSelectionRange(nextLink.start,
0355: nextLink.length);
0356: }
0357: e.detail = SWT.TRAVERSE_NONE;
0358: e.doit = true;
0359: break;
0360: case SWT.TRAVERSE_TAB_PREVIOUS:
0361: // Handle Ctrl-Shift-Tab
0362: if ((e.stateMask & SWT.CTRL) != 0) {
0363: if (e.widget == firstText) {
0364: return;
0365: } else {
0366: e.doit = false;
0367: previousTabAbortTraversal = true;
0368: firstText
0369: .traverse(SWT.TRAVERSE_TAB_PREVIOUS);
0370: return;
0371: }
0372: }
0373: if (previousTabAbortTraversal) {
0374: previousTabAbortTraversal = false;
0375: return;
0376: }
0377: // Find the previous link in current widget, if applicable
0378: // Stop at top of widget also
0379: StyleRange previousLink = findPreviousLink(text);
0380: if (previousLink == null) {
0381: if (text.getSelection().x == 0) {
0382: // go to the previous widget, focus at end
0383: StyledText previousText = previousText(text);
0384: previousText.setSelection(previousText
0385: .getCharCount());
0386: previousLink = findPreviousLink(previousText);
0387: if (previousLink == null) {
0388: focusOn(previousText, 0);
0389: } else {
0390: focusOn(previousText, previousText
0391: .getSelection().x);
0392: previousText.setSelectionRange(
0393: previousLink.start,
0394: previousLink.length);
0395: }
0396: } else {
0397: // stay at top of this widget
0398: focusOn(text, 0);
0399: }
0400: } else {
0401: // focusOn: allow none tab traversals to align
0402: focusOn(text, text.getSelection().x);
0403: text.setSelectionRange(previousLink.start,
0404: previousLink.length);
0405: }
0406: e.detail = SWT.TRAVERSE_NONE;
0407: e.doit = true;
0408: break;
0409: default:
0410: break;
0411: }
0412: }
0413: });
0414:
0415: styledText.addKeyListener(new KeyListener() {
0416: public void keyReleased(KeyEvent e) {
0417: //Ignore a key release
0418: }
0419:
0420: public void keyPressed(KeyEvent event) {
0421: StyledText text = (StyledText) event.widget;
0422: if (event.character == ' ' || event.character == SWT.CR) {
0423: if (text != null) {
0424: WelcomeItem item = (WelcomeItem) text.getData();
0425:
0426: //Be sure we are in the selection
0427: int offset = text.getSelection().x + 1;
0428:
0429: if (item.isLinkAt(offset)) {
0430: text.setCursor(busyCursor);
0431: item.triggerLinkAt(offset);
0432: StyleRange selectionRange = getCurrentLink(text);
0433: text.setSelectionRange(
0434: selectionRange.start,
0435: selectionRange.length);
0436: text.setCursor(null);
0437: }
0438: }
0439: return;
0440: }
0441:
0442: // When page down is pressed, move the cursor to the next item in the
0443: // welcome page. Note that this operation wraps (pages to the top item
0444: // when the last item is reached).
0445: if (event.keyCode == SWT.PAGE_DOWN) {
0446: focusOn(nextText(text), 0);
0447: return;
0448: }
0449:
0450: // When page up is pressed, move the cursor to the previous item in the
0451: // welcome page. Note that this operation wraps (pages to the bottom item
0452: // when the first item is reached).
0453: if (event.keyCode == SWT.PAGE_UP) {
0454: focusOn(previousText(text), 0);
0455: return;
0456: }
0457: }
0458: });
0459:
0460: styledText.addFocusListener(new FocusAdapter() {
0461: public void focusLost(FocusEvent e) {
0462: // Remember current text widget
0463: lastNavigatedText = (StyledText) e.widget;
0464: }
0465:
0466: public void focusGained(FocusEvent e) {
0467: currentText = (StyledText) e.widget;
0468:
0469: // Remove highlighted selection if text widget has changed
0470: if ((currentText != lastNavigatedText)
0471: && (lastNavigatedText != null)) {
0472: lastNavigatedText.setSelection(lastNavigatedText
0473: .getSelection().x);
0474: }
0475:
0476: // enable/disable copy action
0477: copyAction
0478: .setEnabled(currentText.getSelectionCount() > 0);
0479: }
0480: });
0481:
0482: styledText.addSelectionListener(new SelectionAdapter() {
0483: public void widgetSelected(SelectionEvent e) {
0484: // enable/disable copy action
0485: StyledText text = (StyledText) e.widget;
0486: copyAction.setEnabled(text.getSelectionCount() > 0);
0487: }
0488: });
0489: }
0490:
0491: /**
0492: * Creates the wizard's title area.
0493: *
0494: * @param parent the SWT parent for the title area composite
0495: * @return the created info area composite
0496: */
0497: private Composite createInfoArea(Composite parent) {
0498: // Create the title area which will contain
0499: // a title, message, and image.
0500: this .scrolledComposite = new ScrolledComposite(parent,
0501: SWT.V_SCROLL | SWT.H_SCROLL);
0502: this .scrolledComposite.setLayoutData(new GridData(
0503: GridData.FILL_BOTH));
0504: final Composite infoArea = new Composite(
0505: this .scrolledComposite, SWT.NONE);
0506: GridLayout layout = new GridLayout();
0507: layout.marginHeight = 10;
0508: layout.verticalSpacing = 5;
0509: layout.numColumns = 2;
0510: infoArea.setLayout(layout);
0511: GridData data = new GridData(GridData.FILL_BOTH);
0512: infoArea.setLayoutData(data);
0513: boolean wrapped = parser.isFormatWrapped();
0514: int HINDENT = 20;
0515:
0516: // Get the background color for the title area
0517: Display display = parent.getDisplay();
0518: Color background = JFaceColors.getBannerBackground(display);
0519: Color foreground = JFaceColors.getBannerForeground(display);
0520: infoArea.setBackground(background);
0521:
0522: int textStyle = SWT.MULTI | SWT.READ_ONLY;
0523: if (wrapped) {
0524: textStyle = textStyle | SWT.WRAP;
0525: }
0526: StyledText sampleStyledText = null;
0527: // Create the intro item
0528: WelcomeItem item = getIntroItem();
0529: if (item != null) {
0530: StyledText styledText = new StyledText(infoArea, textStyle);
0531: this .texts.add(styledText);
0532: sampleStyledText = styledText;
0533: styledText.setCursor(null);
0534: JFaceColors.setColors(styledText, foreground, background);
0535: styledText.setText(getIntroItem().getText());
0536: setBoldRanges(styledText, item.getBoldRanges());
0537: setLinkRanges(styledText, item.getActionRanges());
0538: setLinkRanges(styledText, item.getHelpRanges());
0539: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
0540: gd.horizontalSpan = 2;
0541: gd.horizontalIndent = HINDENT;
0542: gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
0543: styledText.setLayoutData(gd);
0544: styledText.setData(item);
0545: addListeners(styledText);
0546:
0547: Label spacer = new Label(infoArea, SWT.NONE);
0548: spacer.setBackground(background);
0549: gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
0550: gd.horizontalSpan = 2;
0551: spacer.setLayoutData(gd);
0552: }
0553: firstText = sampleStyledText;
0554:
0555: // Create the welcome items
0556: Label imageLabel = null;
0557: WelcomeItem[] items = getItems();
0558: for (int i = 0; i < items.length; i++) {
0559: Label label = new Label(infoArea, SWT.NONE);
0560: label.setBackground(background);
0561: label
0562: .setImage(PlatformUI
0563: .getWorkbench()
0564: .getSharedImages()
0565: .getImage(
0566: IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM));
0567: GridData gd = new GridData();
0568: gd.horizontalIndent = HINDENT;
0569: gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
0570: label.setLayoutData(gd);
0571: if (imageLabel == null) {
0572: imageLabel = label;
0573: }
0574:
0575: StyledText styledText = new StyledText(infoArea, textStyle);
0576: this .texts.add(styledText);
0577: sampleStyledText = styledText;
0578: styledText.setCursor(null);
0579: JFaceColors.setColors(styledText, foreground, background);
0580: styledText.setText(items[i].getText());
0581: setBoldRanges(styledText, items[i].getBoldRanges());
0582: setLinkRanges(styledText, items[i].getActionRanges());
0583: setLinkRanges(styledText, items[i].getHelpRanges());
0584: gd = new GridData(GridData.FILL_HORIZONTAL);
0585: gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
0586: gd.verticalSpan = 2;
0587: styledText.setLayoutData(gd);
0588: styledText.setData(items[i]);
0589: addListeners(styledText);
0590:
0591: Label spacer = new Label(infoArea, SWT.NONE);
0592: spacer.setBackground(background);
0593: gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
0594: gd.horizontalSpan = 2;
0595: spacer.setLayoutData(gd);
0596:
0597: // create context menu
0598: MenuManager menuMgr = new MenuManager("#PopUp"); //$NON-NLS-1$
0599: menuMgr.add(copyAction);
0600: styledText.setMenu(menuMgr.createContextMenu(styledText));
0601: }
0602:
0603: lastText = sampleStyledText;
0604: this .scrolledComposite.setContent(infoArea);
0605: Point p = infoArea.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
0606: this .scrolledComposite.setMinHeight(p.y);
0607: if (wrapped) {
0608: // introduce a horizontal scroll bar after a minimum width is reached
0609: this .scrolledComposite.setMinWidth(WRAP_MIN_WIDTH);
0610: } else {
0611: this .scrolledComposite.setMinWidth(p.x);
0612: }
0613: this .scrolledComposite.setExpandHorizontal(true);
0614: this .scrolledComposite.setExpandVertical(true);
0615:
0616: // When the welcome editor is resized, we need to set the width hint for
0617: // wrapped StyledText widgets so that the wrapped height will be recalculated.
0618: if (wrapped && (imageLabel != null)) {
0619: // figure out how wide the StyledText widgets should be, do this by first
0620: // calculating the width of the area not used by styled text widgets
0621: Rectangle bounds = imageLabel.getBounds();
0622: final int adjust = HINDENT + bounds.width
0623: + layout.verticalSpacing + (layout.marginWidth * 2);
0624: final int adjustFirst = HINDENT + (layout.marginWidth * 2);
0625: infoArea.addListener(SWT.Resize, new Listener() {
0626: public void handleEvent(Event event) {
0627: int w = scrolledComposite.getClientArea().width;
0628: // if the horizontal scroll bar exists, we want to wrap to the
0629: // minimum wrap width
0630: if (w < WRAP_MIN_WIDTH) {
0631: w = WRAP_MIN_WIDTH;
0632: }
0633: for (int i = 0; i < texts.size(); i++) {
0634: int extent;
0635: if (i == 0) {
0636: extent = w - adjustFirst;
0637: } else {
0638: extent = w - adjust;
0639: }
0640: StyledText text = (StyledText) texts.get(i);
0641: Point p = text.computeSize(extent, SWT.DEFAULT,
0642: false);
0643: ((GridData) text.getLayoutData()).widthHint = p.x;
0644: }
0645: // reset the scrolled composite height since the height of the
0646: // styled text widgets have changed
0647: Point p = infoArea.computeSize(SWT.DEFAULT,
0648: SWT.DEFAULT, true);
0649: scrolledComposite.setMinHeight(p.y);
0650: }
0651: });
0652: }
0653:
0654: // Adjust the scrollbar increments
0655: if (sampleStyledText == null) {
0656: this .scrolledComposite.getHorizontalBar().setIncrement(
0657: HORZ_SCROLL_INCREMENT);
0658: this .scrolledComposite.getVerticalBar().setIncrement(
0659: VERT_SCROLL_INCREMENT);
0660: } else {
0661: GC gc = new GC(sampleStyledText);
0662: int width = gc.getFontMetrics().getAverageCharWidth();
0663: gc.dispose();
0664: this .scrolledComposite.getHorizontalBar().setIncrement(
0665: width);
0666: this .scrolledComposite.getVerticalBar().setIncrement(
0667: sampleStyledText.getLineHeight());
0668: }
0669: return infoArea;
0670: }
0671:
0672: /**
0673: * Creates the SWT controls for this workbench part.
0674: * <p>
0675: * Clients should not call this method (the workbench calls this method at
0676: * appropriate times).
0677: * </p>
0678: * <p>
0679: * For implementors this is a multi-step process:
0680: * <ol>
0681: * <li>Create one or more controls within the parent.</li>
0682: * <li>Set the parent layout as needed.</li>
0683: * <li>Register any global actions with the <code>IActionService</code>.</li>
0684: * <li>Register any popup menus with the <code>IActionService</code>.</li>
0685: * <li>Register a selection provider with the <code>ISelectionService</code>
0686: * (optional). </li>
0687: * </ol>
0688: * </p>
0689: *
0690: * @param parent the parent control
0691: */
0692: public void createPartControl(Composite parent) {
0693: // read our contents
0694: readFile();
0695: if (parser == null) {
0696: return;
0697: }
0698:
0699: handCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
0700: busyCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT);
0701:
0702: editorComposite = new Composite(parent, SWT.NONE);
0703: GridLayout layout = new GridLayout();
0704: layout.marginHeight = 0;
0705: layout.marginWidth = 0;
0706: layout.verticalSpacing = 0;
0707: layout.horizontalSpacing = 0;
0708: editorComposite.setLayout(layout);
0709:
0710: createTitleArea(editorComposite);
0711:
0712: Label titleBarSeparator = new Label(editorComposite,
0713: SWT.HORIZONTAL | SWT.SEPARATOR);
0714: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
0715: titleBarSeparator.setLayoutData(gd);
0716:
0717: createInfoArea(editorComposite);
0718:
0719: getSite().getWorkbenchWindow().getWorkbench().getHelpSystem()
0720: .setHelp(editorComposite,
0721: IIDEHelpContextIds.WELCOME_EDITOR);
0722:
0723: this .colorListener = new IPropertyChangeListener() {
0724: public void propertyChange(PropertyChangeEvent event) {
0725: if (event.getProperty().equals(
0726: JFacePreferences.HYPERLINK_COLOR)) {
0727: Color fg = JFaceColors
0728: .getHyperlinkText(editorComposite
0729: .getDisplay());
0730: Iterator links = hyperlinkRanges.iterator();
0731: while (links.hasNext()) {
0732: StyleRange range = (StyleRange) links.next();
0733: range.foreground = fg;
0734: }
0735: }
0736: }
0737: };
0738:
0739: JFacePreferences.getPreferenceStore()
0740: .addPropertyChangeListener(this .colorListener);
0741:
0742: }
0743:
0744: /**
0745: * Creates the wizard's title area.
0746: *
0747: * @param parent the SWT parent for the title area composite
0748: * @return the created title area composite
0749: */
0750: private Composite createTitleArea(Composite parent) {
0751: // Get the background color for the title area
0752: Display display = parent.getDisplay();
0753: Color background = JFaceColors.getBannerBackground(display);
0754: Color foreground = JFaceColors.getBannerForeground(display);
0755:
0756: // Create the title area which will contain
0757: // a title, message, and image.
0758: Composite titleArea = new Composite(parent, SWT.NONE
0759: | SWT.NO_FOCUS);
0760: GridLayout layout = new GridLayout();
0761: layout.marginHeight = 0;
0762: layout.marginWidth = 0;
0763: layout.verticalSpacing = 0;
0764: layout.horizontalSpacing = 0;
0765: layout.numColumns = 2;
0766: titleArea.setLayout(layout);
0767: titleArea.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
0768: titleArea.setBackground(background);
0769:
0770: // Message label
0771: final CLabel messageLabel = new CLabel(titleArea, SWT.LEFT) {
0772: protected String shortenText(GC gc, String text, int width) {
0773: if (gc.textExtent(text, SWT.DRAW_MNEMONIC).x <= width) {
0774: return text;
0775: }
0776: final String ellipsis = "..."; //$NON-NLS-1$
0777: int ellipseWidth = gc.textExtent(ellipsis,
0778: SWT.DRAW_MNEMONIC).x;
0779: int length = text.length();
0780: int end = length - 1;
0781: while (end > 0) {
0782: text = text.substring(0, end);
0783: int l1 = gc.textExtent(text, SWT.DRAW_MNEMONIC).x;
0784: if (l1 + ellipseWidth <= width) {
0785: return text + ellipsis;
0786: }
0787: end--;
0788: }
0789: return text + ellipsis;
0790: }
0791: };
0792: JFaceColors.setColors(messageLabel, foreground, background);
0793: messageLabel.setText(getBannerTitle());
0794: messageLabel.setFont(JFaceResources.getHeaderFont());
0795:
0796: final IPropertyChangeListener fontListener = new IPropertyChangeListener() {
0797: public void propertyChange(PropertyChangeEvent event) {
0798: if (JFaceResources.HEADER_FONT.equals(event
0799: .getProperty())) {
0800: messageLabel
0801: .setFont(JFaceResources.getHeaderFont());
0802: }
0803: }
0804: };
0805:
0806: messageLabel.addDisposeListener(new DisposeListener() {
0807: public void widgetDisposed(DisposeEvent event) {
0808: JFaceResources.getFontRegistry().removeListener(
0809: fontListener);
0810: }
0811: });
0812:
0813: JFaceResources.getFontRegistry().addListener(fontListener);
0814:
0815: GridData gd = new GridData(GridData.FILL_BOTH);
0816: messageLabel.setLayoutData(gd);
0817:
0818: // Title image
0819: Label titleImage = new Label(titleArea, SWT.LEFT);
0820: titleImage.setBackground(background);
0821: titleImage
0822: .setImage(PlatformUI
0823: .getWorkbench()
0824: .getSharedImages()
0825: .getImage(
0826: IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER));
0827: gd = new GridData();
0828: gd.horizontalAlignment = GridData.END;
0829: titleImage.setLayoutData(gd);
0830:
0831: return titleArea;
0832: }
0833:
0834: /**
0835: * The <code>WorkbenchPart</code> implementation of this
0836: * <code>IWorkbenchPart</code> method disposes the title image
0837: * loaded by <code>setInitializationData</code>. Subclasses may extend.
0838: */
0839: public void dispose() {
0840: super .dispose();
0841: if (busyCursor != null) {
0842: busyCursor.dispose();
0843: }
0844: if (handCursor != null) {
0845: handCursor.dispose();
0846: }
0847: if (this .colorListener != null) {
0848: JFacePreferences.getPreferenceStore()
0849: .removePropertyChangeListener(this .colorListener);
0850: }
0851: }
0852:
0853: /* (non-Javadoc)
0854: * Saves the contents of this editor.
0855: * <p>
0856: * Subclasses must override this method to implement the open-save-close lifecycle
0857: * for an editor. For greater details, see <code>IEditorPart</code>
0858: * </p>
0859: *
0860: * @see IEditorPart
0861: */
0862: public void doSave(IProgressMonitor monitor) {
0863: // do nothing
0864: }
0865:
0866: /* (non-Javadoc)
0867: * Saves the contents of this editor to another object.
0868: * <p>
0869: * Subclasses must override this method to implement the open-save-close lifecycle
0870: * for an editor. For greater details, see <code>IEditorPart</code>
0871: * </p>
0872: *
0873: * @see IEditorPart
0874: */
0875: public void doSaveAs() {
0876: // do nothing
0877: }
0878:
0879: /**
0880: * Returns the title obtained from the parser
0881: */
0882: private String getBannerTitle() {
0883: if (parser.getTitle() == null) {
0884: return ""; //$NON-NLS-1$
0885: }
0886: return parser.getTitle();
0887: }
0888:
0889: /**
0890: * Returns the intro item or <code>null</code>
0891: */
0892: private WelcomeItem getIntroItem() {
0893: return parser.getIntroItem();
0894: }
0895:
0896: /**
0897: * Returns the welcome items
0898: */
0899: private WelcomeItem[] getItems() {
0900: return parser.getItems();
0901: }
0902:
0903: /* (non-Javadoc)
0904: * Sets the cursor and selection state for this editor to the passage defined
0905: * by the given marker.
0906: * <p>
0907: * Subclasses may override. For greater details, see <code>IEditorPart</code>
0908: * </p>
0909: *
0910: * @see IEditorPart
0911: */
0912: public void gotoMarker(IMarker marker) {
0913: // do nothing
0914: }
0915:
0916: /* (non-Javadoc)
0917: * Initializes the editor part with a site and input.
0918: * <p>
0919: * Subclasses of <code>EditorPart</code> must implement this method. Within
0920: * the implementation subclasses should verify that the input type is acceptable
0921: * and then save the site and input. Here is sample code:
0922: * </p>
0923: * <pre>
0924: * if (!(input instanceof IFileEditorInput))
0925: * throw new PartInitException("Invalid Input: Must be IFileEditorInput");
0926: * setSite(site);
0927: * setInput(editorInput);
0928: * </pre>
0929: */
0930: public void init(IEditorSite site, IEditorInput input)
0931: throws PartInitException {
0932: if (!(input instanceof WelcomeEditorInput)) {
0933: throw new PartInitException(
0934: "Invalid Input: Must be WelcomeEditorInput"); //$NON-NLS-1$
0935: }
0936: setSite(site);
0937: setInput(input);
0938: }
0939:
0940: /* (non-Javadoc)
0941: * Returns whether the contents of this editor have changed since the last save
0942: * operation.
0943: * <p>
0944: * Subclasses must override this method to implement the open-save-close lifecycle
0945: * for an editor. For greater details, see <code>IEditorPart</code>
0946: * </p>
0947: *
0948: * @see IEditorPart
0949: */
0950: public boolean isDirty() {
0951: return false;
0952: }
0953:
0954: /* (non-Javadoc)
0955: * Returns whether the "save as" operation is supported by this editor.
0956: * <p>
0957: * Subclasses must override this method to implement the open-save-close lifecycle
0958: * for an editor. For greater details, see <code>IEditorPart</code>
0959: * </p>
0960: *
0961: * @see IEditorPart
0962: */
0963: public boolean isSaveAsAllowed() {
0964: return false;
0965: }
0966:
0967: /**
0968: * Read the contents of the welcome page
0969: *
0970: * @param is the <code>InputStream</code> to parse
0971: * @throws IOException if there is a problem parsing the stream.
0972: */
0973: public void read(InputStream is) throws IOException {
0974: try {
0975: parser = new WelcomeParser();
0976: } catch (ParserConfigurationException e) {
0977: throw (IOException) (new IOException().initCause(e));
0978: } catch (SAXException e) {
0979: throw (IOException) (new IOException().initCause(e));
0980: }
0981: parser.parse(is);
0982: }
0983:
0984: /**
0985: * Reads the welcome file
0986: */
0987: public void readFile() {
0988: URL url = ((WelcomeEditorInput) getEditorInput())
0989: .getAboutInfo().getWelcomePageURL();
0990:
0991: if (url == null) {
0992: // should not happen
0993: return;
0994: }
0995:
0996: InputStream is = null;
0997: try {
0998: is = url.openStream();
0999: read(is);
1000: } catch (IOException e) {
1001: IStatus status = new Status(IStatus.ERROR,
1002: IDEWorkbenchPlugin.IDE_WORKBENCH, 1,
1003: IDEWorkbenchMessages.WelcomeEditor_accessException,
1004: e);
1005: IDEWorkbenchPlugin.log(
1006: IDEWorkbenchMessages.WelcomeEditor_readFileError,
1007: status);
1008: } finally {
1009: try {
1010: if (is != null) {
1011: is.close();
1012: }
1013: } catch (IOException e) {
1014: }
1015: }
1016: }
1017:
1018: /**
1019: * Sets the styled text's bold ranges
1020: */
1021: private void setBoldRanges(StyledText styledText, int[][] boldRanges) {
1022: for (int i = 0; i < boldRanges.length; i++) {
1023: StyleRange r = new StyleRange(boldRanges[i][0],
1024: boldRanges[i][1], null, null, SWT.BOLD);
1025: styledText.setStyleRange(r);
1026: }
1027: }
1028:
1029: /**
1030: * Asks this part to take focus within the workbench.
1031: * <p>
1032: * Clients should not call this method (the workbench calls this method at
1033: * appropriate times).
1034: * </p>
1035: */
1036: public void setFocus() {
1037: if ((editorComposite != null) && (lastNavigatedText == null)
1038: && (currentText == null)) {
1039: editorComposite.setFocus();
1040: }
1041: }
1042:
1043: /**
1044: * Sets the styled text's link (blue) ranges
1045: */
1046: private void setLinkRanges(StyledText styledText, int[][] linkRanges) {
1047: //Color fg = styledText.getDisplay().getSystemColor(SWT.COLOR_BLUE);
1048: Color fg = JFaceColors.getHyperlinkText(styledText.getShell()
1049: .getDisplay());
1050: for (int i = 0; i < linkRanges.length; i++) {
1051: StyleRange r = new StyleRange(linkRanges[i][0],
1052: linkRanges[i][1], fg, null);
1053: styledText.setStyleRange(r);
1054: hyperlinkRanges.add(r);
1055: }
1056: }
1057:
1058: }
|