| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.ide.dialogs; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CLabel; |
| import org.eclipse.swt.custom.ScrolledComposite; |
| import org.eclipse.swt.custom.StyleRange; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseMoveListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.TraverseEvent; |
| import org.eclipse.swt.events.TraverseListener; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.preference.JFacePreferences; |
| import org.eclipse.jface.resource.JFaceColors; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorSite; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.help.WorkbenchHelp; |
| import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages; |
| import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; |
| import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; |
| import org.eclipse.ui.internal.ide.IHelpContextIds; |
| import org.eclipse.ui.part.EditorPart; |
| |
| import org.xml.sax.SAXException; |
| |
| /** |
| * A "fake" editor to show a welcome page |
| * The contents of this page are supplied in the product configuration |
| * |
| * PRIVATE |
| * This class is internal to the workbench and must not be called outside the workbench |
| */ |
| public class WelcomeEditor extends EditorPart { |
| |
| private final static int HORZ_SCROLL_INCREMENT = 20; |
| private final static int VERT_SCROLL_INCREMENT = 20; |
| // width at which wrapping will stop and a horizontal scroll bar will be |
| // introduced |
| private final static int WRAP_MIN_WIDTH = 150; |
| |
| private Composite editorComposite; |
| |
| private Cursor handCursor; |
| private Cursor busyCursor; |
| |
| private WelcomeParser parser; |
| |
| private ArrayList hyperlinkRanges = new ArrayList(); |
| private ArrayList texts = new ArrayList(); |
| private ScrolledComposite scrolledComposite; |
| |
| private IPropertyChangeListener colorListener; |
| private boolean mouseDown = false; |
| private boolean dragEvent = false; |
| |
| private StyledText firstText, lastText; |
| private StyledText lastNavigatedText, currentText; |
| private boolean nextTabAbortTraversal, previousTabAbortTraversal = false; |
| |
| private WelcomeEditorCopyAction copyAction; |
| |
| /** |
| * Create a new instance of the welcome editor |
| */ |
| public WelcomeEditor() { |
| super(); |
| setTitle(IDEWorkbenchMessages.getString("WelcomeEditor.title")); //$NON-NLS-1$ |
| copyAction = new WelcomeEditorCopyAction(this); |
| copyAction.setEnabled(false); |
| } |
| |
| /** |
| * Update the welcome page to start at the |
| * beginning of the text. |
| */ |
| private void focusOn(StyledText newText, int caretOffset){ |
| if(newText == null) |
| return; |
| newText.setFocus(); |
| newText.setCaretOffset(caretOffset); |
| scrolledComposite.setOrigin(0,newText.getLocation().y); |
| } |
| |
| /** |
| * Finds the next text |
| */ |
| private StyledText nextText(StyledText text){ |
| int index = 0; |
| if(text == null) |
| return (StyledText) texts.get(0); |
| else |
| index = texts.indexOf(text); |
| |
| //If we are not at the end.... |
| if(index < texts.size() - 1) |
| return (StyledText) texts.get(index + 1); |
| else |
| return (StyledText) texts.get(0); |
| } |
| |
| /** |
| * Finds the previous text |
| */ |
| private StyledText previousText(StyledText text){ |
| int index = 0; |
| if(text == null) |
| return (StyledText) texts.get(0); |
| else |
| index = texts.indexOf(text); |
| |
| //If we are at the beginning.... |
| if(index == 0) |
| return (StyledText) texts.get(texts.size() - 1); |
| else |
| return (StyledText) texts.get(index - 1); |
| } |
| |
| /** |
| * Returns the current text. |
| */ |
| protected StyledText getCurrentText() { |
| return currentText; |
| } |
| |
| /** |
| * Returns the copy action. |
| */ |
| protected WelcomeEditorCopyAction getCopyAction() { |
| return copyAction; |
| } |
| |
| /** |
| * Finds the next link after the current selection. |
| */ |
| private StyleRange findNextLink(StyledText text) { |
| if(text == null) |
| return null; |
| |
| WelcomeItem item = (WelcomeItem)text.getData(); |
| StyleRange[] ranges = text.getStyleRanges(); |
| int currentSelectionEnd = text.getSelection().y; |
| |
| for (int i = 0; i < ranges.length; i++) { |
| if(ranges[i].start >= currentSelectionEnd) |
| if (item.isLinkAt(ranges[i].start)) |
| return ranges[i]; |
| } |
| return null; |
| } |
| |
| /** |
| * Finds the previous link before the current selection. |
| */ |
| private StyleRange findPreviousLink(StyledText text) { |
| if(text == null) |
| return null; |
| |
| WelcomeItem item = (WelcomeItem)text.getData(); |
| StyleRange[] ranges = text.getStyleRanges(); |
| int currentSelectionStart = text.getSelection().x; |
| |
| for (int i = ranges.length - 1; i > -1; i--) { |
| if((ranges[i].start + ranges[i].length) < currentSelectionStart) |
| if (item.isLinkAt(ranges[i].start + ranges[i].length - 1)) |
| return ranges[i]; |
| } |
| return null; |
| } |
| |
| /** |
| * Finds the current link of the current selection. |
| */ |
| protected StyleRange getCurrentLink(StyledText text){ |
| StyleRange[] ranges = text.getStyleRanges(); |
| int currentSelectionEnd = text.getSelection().y; |
| int currentSelectionStart = text.getSelection().x; |
| |
| for (int i = 0; i < ranges.length; i++) { |
| if((currentSelectionStart >= ranges[i].start) && |
| (currentSelectionEnd <= (ranges[i].start + ranges[i].length))) { |
| return ranges[i]; |
| } |
| } |
| return null; |
| } |
| /** |
| * Adds listeners to the given styled text |
| */ |
| private void addListeners(StyledText styledText) { |
| styledText.addMouseListener(new MouseAdapter() { |
| public void mouseDown(MouseEvent e) { |
| if (e.button != 1) { |
| return; |
| } |
| mouseDown = true; |
| } |
| public void mouseUp(MouseEvent e) { |
| mouseDown = false; |
| StyledText text = (StyledText)e.widget; |
| WelcomeItem item = (WelcomeItem)e.widget.getData(); |
| int offset = text.getCaretOffset(); |
| if (dragEvent) { |
| dragEvent = false; |
| if (item.isLinkAt(offset)) { |
| text.setCursor(handCursor); |
| } |
| } else if (item.isLinkAt(offset)) { |
| text.setCursor(busyCursor); |
| if (e.button == 1) { |
| item.triggerLinkAt(offset); |
| StyleRange selectionRange = getCurrentLink(text); |
| text.setSelectionRange(selectionRange.start, selectionRange.length); |
| text.setCursor(null); |
| } |
| } |
| } |
| }); |
| |
| styledText.addMouseMoveListener(new MouseMoveListener() { |
| public void mouseMove(MouseEvent e) { |
| // Do not change cursor on drag events |
| if (mouseDown) { |
| if (!dragEvent) { |
| StyledText text = (StyledText)e.widget; |
| text.setCursor(null); |
| } |
| dragEvent = true; |
| return; |
| } |
| StyledText text = (StyledText)e.widget; |
| WelcomeItem item = (WelcomeItem)e.widget.getData(); |
| int offset = -1; |
| try { |
| offset = text.getOffsetAtLocation(new Point(e.x, e.y)); |
| } catch (IllegalArgumentException ex) { |
| // location is not over a character |
| } |
| if (offset == -1) |
| text.setCursor(null); |
| else if (item.isLinkAt(offset)) |
| text.setCursor(handCursor); |
| else |
| text.setCursor(null); |
| } |
| }); |
| |
| styledText.addTraverseListener(new TraverseListener() { |
| public void keyTraversed(TraverseEvent e) { |
| StyledText text = (StyledText)e.widget; |
| |
| switch (e.detail) { |
| case SWT.TRAVERSE_ESCAPE: |
| e.doit = true; |
| break; |
| case SWT.TRAVERSE_TAB_NEXT: |
| // Handle Ctrl-Tab |
| if ((e.stateMask & SWT.CTRL) != 0) { |
| if (e.widget == lastText) |
| return; |
| else { |
| e.doit = false; |
| nextTabAbortTraversal = true; |
| lastText.traverse(SWT.TRAVERSE_TAB_NEXT); |
| return; |
| } |
| } |
| if (nextTabAbortTraversal) { |
| nextTabAbortTraversal = false; |
| return; |
| } |
| // Find the next link in current widget, if applicable |
| // Stop at top of widget |
| StyleRange nextLink = findNextLink(text); |
| if (nextLink == null) { |
| // go to the next widget, focus at beginning |
| StyledText nextText = nextText(text); |
| nextText.setSelection(0); |
| focusOn(nextText,0); |
| } |
| else { |
| // focusOn: allow none tab traversals to align |
| focusOn(text, text.getSelection().x); |
| text.setSelectionRange(nextLink.start, nextLink.length); |
| } |
| e.detail = SWT.TRAVERSE_NONE; |
| e.doit = true; |
| break; |
| case SWT.TRAVERSE_TAB_PREVIOUS: |
| // Handle Ctrl-Shift-Tab |
| if ((e.stateMask & SWT.CTRL) != 0) { |
| if (e.widget == firstText) |
| return; |
| else { |
| e.doit = false; |
| previousTabAbortTraversal = true; |
| firstText.traverse(SWT.TRAVERSE_TAB_PREVIOUS); |
| return; |
| } |
| } |
| if (previousTabAbortTraversal) { |
| previousTabAbortTraversal = false; |
| return; |
| } |
| // Find the previous link in current widget, if applicable |
| // Stop at top of widget also |
| StyleRange previousLink = findPreviousLink(text); |
| if (previousLink == null) { |
| if (text.getSelection().x == 0) { |
| // go to the previous widget, focus at end |
| StyledText previousText = previousText(text); |
| previousText.setSelection(previousText.getCharCount()); |
| previousLink = findPreviousLink(previousText); |
| if (previousLink == null) |
| focusOn(previousText,0); |
| else { |
| focusOn(previousText, previousText.getSelection().x); |
| previousText.setSelectionRange(previousLink.start, previousLink.length); |
| } |
| } |
| else { |
| // stay at top of this widget |
| focusOn(text, 0); |
| } |
| } |
| else { |
| // focusOn: allow none tab traversals to align |
| focusOn(text, text.getSelection().x); |
| text.setSelectionRange(previousLink.start, previousLink.length); |
| } |
| e.detail = SWT.TRAVERSE_NONE; |
| e.doit = true; |
| break; |
| default: |
| break; |
| } |
| } |
| }); |
| |
| styledText.addKeyListener(new KeyListener() { |
| public void keyReleased(KeyEvent e){ |
| //Ignore a key release |
| } |
| public void keyPressed (KeyEvent event){ |
| StyledText text = (StyledText)event.widget; |
| if(event.character == ' ' || event.character == SWT.CR){ |
| if(text != null) { |
| WelcomeItem item = (WelcomeItem)text.getData(); |
| |
| //Be sure we are in the selection |
| int offset = text.getSelection().x + 1; |
| |
| if (item.isLinkAt(offset)) { |
| text.setCursor(busyCursor); |
| item.triggerLinkAt(offset); |
| StyleRange selectionRange = getCurrentLink(text); |
| text.setSelectionRange(selectionRange.start, selectionRange.length); |
| text.setCursor(null); |
| } |
| } |
| return; |
| } |
| |
| // When page down is pressed, move the cursor to the next item in the |
| // welcome page. Note that this operation wraps (pages to the top item |
| // when the last item is reached). |
| if(event.keyCode == SWT.PAGE_DOWN){ |
| focusOn(nextText(text),0); |
| return; |
| } |
| |
| // When page up is pressed, move the cursor to the previous item in the |
| // welcome page. Note that this operation wraps (pages to the bottom item |
| // when the first item is reached). |
| if(event.keyCode == SWT.PAGE_UP){ |
| focusOn(previousText(text),0); |
| return; |
| } |
| } |
| }); |
| |
| styledText.addFocusListener(new FocusAdapter() { |
| public void focusLost(FocusEvent e) { |
| // Remember current text widget |
| lastNavigatedText = (StyledText)e.widget; |
| } |
| public void focusGained(FocusEvent e) { |
| currentText = (StyledText)e.widget; |
| |
| // Remove highlighted selection if text widget has changed |
| if ((currentText != lastNavigatedText) && (lastNavigatedText != null)) |
| lastNavigatedText.setSelection(lastNavigatedText.getSelection().x); |
| |
| // enable/disable copy action |
| copyAction.setEnabled(currentText.getSelectionCount()>0); |
| } |
| }); |
| |
| styledText.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| // enable/disable copy action |
| StyledText text = (StyledText)e.widget; |
| copyAction.setEnabled(text.getSelectionCount()>0); |
| } |
| }); |
| } |
| |
| /** |
| * Creates the wizard's title area. |
| * |
| * @param parent the SWT parent for the title area composite |
| * @return the created info area composite |
| */ |
| private Composite createInfoArea(Composite parent) { |
| // Create the title area which will contain |
| // a title, message, and image. |
| this.scrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL); |
| this.scrolledComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| final Composite infoArea = new Composite(this.scrolledComposite, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.marginHeight = 10; |
| layout.verticalSpacing = 5; |
| layout.numColumns = 2; |
| infoArea.setLayout(layout); |
| GridData data = new GridData(GridData.FILL_BOTH); |
| infoArea.setLayoutData(data); |
| boolean wrapped = parser.isFormatWrapped(); |
| int HINDENT = 20; |
| |
| // Get the background color for the title area |
| Display display = parent.getDisplay(); |
| Color background = JFaceColors.getBannerBackground(display); |
| Color foreground = JFaceColors.getBannerForeground(display); |
| infoArea.setBackground(background); |
| |
| int textStyle = SWT.MULTI | SWT.READ_ONLY; |
| if (wrapped) { |
| textStyle = textStyle | SWT.WRAP; |
| } |
| StyledText sampleStyledText = null; |
| // Create the intro item |
| WelcomeItem item = getIntroItem(); |
| if (item != null) { |
| StyledText styledText = new StyledText(infoArea, textStyle); |
| this.texts.add(styledText); |
| sampleStyledText = styledText; |
| styledText.setCursor(null); |
| JFaceColors.setColors(styledText,foreground,background); |
| styledText.setText(getIntroItem().getText()); |
| setBoldRanges(styledText, item.getBoldRanges()); |
| setLinkRanges(styledText, item.getActionRanges()); |
| setLinkRanges(styledText, item.getHelpRanges()); |
| GridData gd = new GridData(GridData.FILL_HORIZONTAL); |
| gd.horizontalSpan = 2; |
| gd.horizontalIndent = HINDENT; |
| gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING; |
| styledText.setLayoutData(gd); |
| styledText.setData(item); |
| addListeners(styledText); |
| |
| Label spacer = new Label(infoArea, SWT.NONE); |
| spacer.setBackground(background); |
| gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); |
| gd.horizontalSpan = 2; |
| spacer.setLayoutData(gd); |
| } |
| firstText = sampleStyledText; |
| |
| // Create the welcome items |
| Label imageLabel = null; |
| WelcomeItem[] items = getItems(); |
| for (int i = 0; i < items.length; i++) { |
| Label label = new Label(infoArea, SWT.NONE); |
| label.setBackground(background); |
| label.setImage( |
| PlatformUI.getWorkbench().getSharedImages().getImage( |
| IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_ITEM)); |
| GridData gd = new GridData(); |
| gd.horizontalIndent = HINDENT; |
| gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING; |
| label.setLayoutData(gd); |
| if (imageLabel == null) { |
| imageLabel = label; |
| } |
| |
| StyledText styledText = new StyledText(infoArea, textStyle); |
| this.texts.add(styledText); |
| sampleStyledText = styledText; |
| styledText.setCursor(null); |
| JFaceColors.setColors(styledText,foreground,background); |
| styledText.setText(items[i].getText()); |
| setBoldRanges(styledText, items[i].getBoldRanges()); |
| setLinkRanges(styledText, items[i].getActionRanges()); |
| setLinkRanges(styledText, items[i].getHelpRanges()); |
| gd = new GridData(GridData.FILL_HORIZONTAL); |
| gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING; |
| gd.verticalSpan = 2; |
| styledText.setLayoutData(gd); |
| styledText.setData(items[i]); |
| addListeners(styledText); |
| |
| Label spacer = new Label(infoArea, SWT.NONE); |
| spacer.setBackground(background); |
| gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); |
| gd.horizontalSpan = 2; |
| spacer.setLayoutData(gd); |
| |
| // create context menu |
| MenuManager menuMgr = new MenuManager("#PopUp"); //$NON-NLS-1$ |
| menuMgr.add(copyAction); |
| styledText.setMenu(menuMgr.createContextMenu(styledText)); |
| } |
| |
| lastText = sampleStyledText; |
| this.scrolledComposite.setContent(infoArea); |
| Point p = infoArea.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); |
| this.scrolledComposite.setMinHeight(p.y); |
| if (wrapped) { |
| // introduce a horizontal scroll bar after a minimum width is reached |
| this.scrolledComposite.setMinWidth(WRAP_MIN_WIDTH); |
| } else { |
| this.scrolledComposite.setMinWidth(p.x); |
| } |
| this.scrolledComposite.setExpandHorizontal(true); |
| this.scrolledComposite.setExpandVertical(true); |
| |
| // When the welcome editor is resized, we need to set the width hint for |
| // wrapped StyledText widgets so that the wrapped height will be recalculated. |
| if (wrapped && (imageLabel != null)) { |
| // figure out how wide the StyledText widgets should be, do this by first |
| // calculating the width of the area not used by styled text widgets |
| Rectangle bounds = imageLabel.getBounds(); |
| final int adjust = HINDENT + bounds.width + layout.verticalSpacing + (layout.marginWidth * 2); |
| final int adjustFirst = HINDENT + (layout.marginWidth * 2); |
| infoArea.addListener(SWT.Resize, new Listener() { |
| public void handleEvent(Event event) { |
| int w = scrolledComposite.getClientArea().width; |
| // if the horizontal scroll bar exists, we want to wrap to the |
| // minimum wrap width |
| if (w < WRAP_MIN_WIDTH) { |
| w = WRAP_MIN_WIDTH; |
| } |
| for (int i=0; i<texts.size(); i++) { |
| int extent; |
| if (i==0) extent = w - adjustFirst; |
| else extent = w - adjust; |
| StyledText text = (StyledText)texts.get(i); |
| Point p = text.computeSize(extent, SWT.DEFAULT, false); |
| ((GridData)text.getLayoutData()).widthHint = p.x; |
| } |
| // reset the scrolled composite height since the height of the |
| // styled text widgets have changed |
| Point p = infoArea.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); |
| scrolledComposite.setMinHeight(p.y); |
| } |
| }); |
| } |
| |
| // Adjust the scrollbar increments |
| if (sampleStyledText == null) { |
| this.scrolledComposite.getHorizontalBar().setIncrement(HORZ_SCROLL_INCREMENT); |
| this.scrolledComposite.getVerticalBar().setIncrement(VERT_SCROLL_INCREMENT); |
| } else { |
| GC gc = new GC(sampleStyledText); |
| int width = gc.getFontMetrics().getAverageCharWidth(); |
| gc.dispose(); |
| this.scrolledComposite.getHorizontalBar().setIncrement(width); |
| this.scrolledComposite.getVerticalBar().setIncrement(sampleStyledText.getLineHeight()); |
| } |
| return infoArea; |
| } |
| |
| |
| /** |
| * Creates the SWT controls for this workbench part. |
| * <p> |
| * Clients should not call this method (the workbench calls this method at |
| * appropriate times). |
| * </p> |
| * <p> |
| * For implementors this is a multi-step process: |
| * <ol> |
| * <li>Create one or more controls within the parent.</li> |
| * <li>Set the parent layout as needed.</li> |
| * <li>Register any global actions with the <code>IActionService</code>.</li> |
| * <li>Register any popup menus with the <code>IActionService</code>.</li> |
| * <li>Register a selection provider with the <code>ISelectionService</code> |
| * (optional). </li> |
| * </ol> |
| * </p> |
| * |
| * @param parent the parent control |
| */ |
| public void createPartControl(Composite parent) { |
| // read our contents |
| readFile(); |
| if (parser == null) |
| return; |
| |
| handCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND); |
| busyCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT); |
| |
| editorComposite = new Composite(parent, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.verticalSpacing = 0; |
| layout.horizontalSpacing = 0; |
| editorComposite.setLayout(layout); |
| |
| createTitleArea(editorComposite); |
| |
| Label titleBarSeparator = new Label(editorComposite, SWT.HORIZONTAL | SWT.SEPARATOR); |
| GridData gd = new GridData(GridData.FILL_HORIZONTAL); |
| titleBarSeparator.setLayoutData(gd); |
| |
| createInfoArea(editorComposite); |
| |
| WorkbenchHelp.setHelp(editorComposite, IHelpContextIds.WELCOME_EDITOR); |
| |
| this.colorListener = |
| new IPropertyChangeListener(){ |
| public void propertyChange(PropertyChangeEvent event){ |
| if(event.getProperty().equals(JFacePreferences.HYPERLINK_COLOR)){ |
| Color fg = JFaceColors.getHyperlinkText(editorComposite.getDisplay()); |
| Iterator links = hyperlinkRanges.iterator(); |
| while(links.hasNext()){ |
| StyleRange range = (StyleRange) links.next(); |
| range.foreground = fg; |
| } |
| } |
| } |
| }; |
| |
| JFacePreferences.getPreferenceStore().addPropertyChangeListener(this.colorListener); |
| |
| } |
| /** |
| * Creates the wizard's title area. |
| * |
| * @param parent the SWT parent for the title area composite |
| * @return the created title area composite |
| */ |
| private Composite createTitleArea(Composite parent) { |
| // Get the background color for the title area |
| Display display = parent.getDisplay(); |
| Color background = JFaceColors.getBannerBackground(display); |
| Color foreground = JFaceColors.getBannerForeground(display); |
| |
| // Create the title area which will contain |
| // a title, message, and image. |
| Composite titleArea = new Composite(parent, SWT.NONE | SWT.NO_FOCUS); |
| GridLayout layout = new GridLayout(); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.verticalSpacing = 0; |
| layout.horizontalSpacing = 0; |
| layout.numColumns = 2; |
| titleArea.setLayout(layout); |
| titleArea.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| titleArea.setBackground(background); |
| |
| // Message label |
| final CLabel messageLabel = new CLabel(titleArea, SWT.LEFT) { |
| protected String shortenText(GC gc, String text, int width) { |
| if (gc.textExtent(text, SWT.DRAW_MNEMONIC).x <= width) return text; |
| final String ellipsis= "..."; //$NON-NLS-1$ |
| int ellipseWidth = gc.textExtent(ellipsis, SWT.DRAW_MNEMONIC).x; |
| int length = text.length(); |
| int end = length - 1; |
| while (end > 0) { |
| text = text.substring(0, end); |
| int l1 = gc.textExtent(text, SWT.DRAW_MNEMONIC).x; |
| if (l1 + ellipseWidth <= width) { |
| return text + ellipsis; |
| } |
| end--; |
| } |
| return text + ellipsis; |
| } |
| }; |
| JFaceColors.setColors(messageLabel,foreground,background); |
| messageLabel.setText(getBannerTitle()); |
| messageLabel.setFont(JFaceResources.getHeaderFont()); |
| |
| final IPropertyChangeListener fontListener = new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if(JFaceResources.HEADER_FONT.equals(event.getProperty())) { |
| messageLabel.setFont(JFaceResources.getHeaderFont()); |
| } |
| } |
| }; |
| |
| messageLabel.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent event) { |
| JFaceResources.getFontRegistry().removeListener(fontListener); |
| } |
| }); |
| |
| JFaceResources.getFontRegistry().addListener(fontListener); |
| |
| |
| GridData gd = new GridData(GridData.FILL_BOTH); |
| messageLabel.setLayoutData(gd); |
| |
| // Title image |
| Label titleImage = new Label(titleArea, SWT.LEFT); |
| titleImage.setBackground(background); |
| titleImage.setImage( |
| PlatformUI.getWorkbench().getSharedImages().getImage( |
| IDEInternalWorkbenchImages.IMG_OBJS_WELCOME_BANNER)); |
| gd = new GridData(); |
| gd.horizontalAlignment = GridData.END; |
| titleImage.setLayoutData(gd); |
| |
| return titleArea; |
| } |
| /** |
| * The <code>WorkbenchPart</code> implementation of this |
| * <code>IWorkbenchPart</code> method disposes the title image |
| * loaded by <code>setInitializationData</code>. Subclasses may extend. |
| */ |
| public void dispose() { |
| super.dispose(); |
| if (busyCursor != null) |
| busyCursor.dispose(); |
| if (handCursor != null) |
| handCursor.dispose(); |
| if (this.colorListener != null) { |
| JFacePreferences.getPreferenceStore(). |
| removePropertyChangeListener(this.colorListener); |
| } |
| } |
| /* (non-Javadoc) |
| * Saves the contents of this editor. |
| * <p> |
| * Subclasses must override this method to implement the open-save-close lifecycle |
| * for an editor. For greater details, see <code>IEditorPart</code> |
| * </p> |
| * |
| * @see IEditorPart |
| */ |
| public void doSave(IProgressMonitor monitor) { |
| // do nothing |
| } |
| /* (non-Javadoc) |
| * Saves the contents of this editor to another object. |
| * <p> |
| * Subclasses must override this method to implement the open-save-close lifecycle |
| * for an editor. For greater details, see <code>IEditorPart</code> |
| * </p> |
| * |
| * @see IEditorPart |
| */ |
| public void doSaveAs() { |
| // do nothing |
| } |
| /** |
| * Returns the title obtained from the parser |
| */ |
| private String getBannerTitle() { |
| if (parser.getTitle() == null) |
| return ""; //$NON-NLS-1$ |
| return parser.getTitle(); |
| } |
| /** |
| * Returns the intro item or <code>null</code> |
| */ |
| private WelcomeItem getIntroItem() { |
| return parser.getIntroItem(); |
| } |
| /** |
| * Returns the welcome items |
| */ |
| private WelcomeItem[] getItems() { |
| return parser.getItems(); |
| } |
| /* (non-Javadoc) |
| * Sets the cursor and selection state for this editor to the passage defined |
| * by the given marker. |
| * <p> |
| * Subclasses may override. For greater details, see <code>IEditorPart</code> |
| * </p> |
| * |
| * @see IEditorPart |
| */ |
| public void gotoMarker(IMarker marker) { |
| // do nothing |
| } |
| /* (non-Javadoc) |
| * Initializes the editor part with a site and input. |
| * <p> |
| * Subclasses of <code>EditorPart</code> must implement this method. Within |
| * the implementation subclasses should verify that the input type is acceptable |
| * and then save the site and input. Here is sample code: |
| * </p> |
| * <pre> |
| * if (!(input instanceof IFileEditorInput)) |
| * throw new PartInitException("Invalid Input: Must be IFileEditorInput"); |
| * setSite(site); |
| * setInput(editorInput); |
| * </pre> |
| */ |
| public void init(IEditorSite site, IEditorInput input) throws PartInitException { |
| if (!(input instanceof WelcomeEditorInput)) |
| throw new PartInitException("Invalid Input: Must be IFileEditorInput"); //$NON-NLS-1$ |
| setSite(site); |
| setInput(input); |
| } |
| |
| /* (non-Javadoc) |
| * Returns whether the contents of this editor have changed since the last save |
| * operation. |
| * <p> |
| * Subclasses must override this method to implement the open-save-close lifecycle |
| * for an editor. For greater details, see <code>IEditorPart</code> |
| * </p> |
| * |
| * @see IEditorPart |
| */ |
| public boolean isDirty() { |
| return false; |
| } |
| /* (non-Javadoc) |
| * Returns whether the "save as" operation is supported by this editor. |
| * <p> |
| * Subclasses must override this method to implement the open-save-close lifecycle |
| * for an editor. For greater details, see <code>IEditorPart</code> |
| * </p> |
| * |
| * @see IEditorPart |
| */ |
| public boolean isSaveAsAllowed() { |
| return false; |
| } |
| /** |
| * Read the contents of the welcome page |
| * |
| * @param is the <code>InputStream</code> to parse |
| * @throws IOException if there is a problem parsing the stream. |
| */ |
| public void read(InputStream is) throws IOException { |
| try { |
| parser = new WelcomeParser(); |
| } |
| catch (ParserConfigurationException e) { |
| throw (IOException) (new IOException().initCause(e)); |
| } |
| catch (SAXException e) { |
| throw (IOException) (new IOException().initCause(e)); |
| } |
| parser.parse(is); |
| } |
| /** |
| * Reads the welcome file |
| */ |
| public void readFile() { |
| URL url = ((WelcomeEditorInput)getEditorInput()).getAboutInfo().getWelcomePageURL(); |
| |
| if (url == null) |
| // should not happen |
| return; |
| |
| InputStream is = null; |
| try { |
| is = url.openStream(); |
| read(is); |
| } |
| catch (IOException e) { |
| IStatus status = new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, IDEWorkbenchMessages.getString("WelcomeEditor.accessException"), e); //$NON-NLS-1$ |
| IDEWorkbenchPlugin.log(IDEWorkbenchMessages.getString("WelcomeEditor.readFileError"), status); //$NON-NLS-1$ |
| } |
| finally { |
| try { |
| if (is != null) |
| is.close(); |
| } catch (IOException e) {} |
| } |
| } |
| /** |
| * Sets the styled text's bold ranges |
| */ |
| private void setBoldRanges(StyledText styledText, int[][] boldRanges) { |
| for (int i = 0; i < boldRanges.length; i++) { |
| StyleRange r = new StyleRange(boldRanges[i][0], boldRanges[i][1], null, null, SWT.BOLD); |
| styledText.setStyleRange(r); |
| } |
| } |
| /** |
| * Asks this part to take focus within the workbench. |
| * <p> |
| * Clients should not call this method (the workbench calls this method at |
| * appropriate times). |
| * </p> |
| */ |
| public void setFocus() { |
| if ((editorComposite != null) && (lastNavigatedText == null) && (currentText == null)) |
| editorComposite.setFocus(); |
| } |
| /** |
| * Sets the styled text's link (blue) ranges |
| */ |
| private void setLinkRanges(StyledText styledText, int[][] linkRanges) { |
| //Color fg = styledText.getDisplay().getSystemColor(SWT.COLOR_BLUE); |
| Color fg = JFaceColors.getHyperlinkText(styledText.getShell().getDisplay()); |
| for (int i = 0; i < linkRanges.length; i++) { |
| StyleRange r = new StyleRange(linkRanges[i][0], linkRanges[i][1], fg, null); |
| styledText.setStyleRange(r); |
| hyperlinkRanges.add(r); |
| } |
| } |
| |
| } |