Mercurial > projects > dwt-addons
diff dwtx/jface/text/information/InformationPresenter.d @ 129:eb30df5ca28b
Added JFace Text sources
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 23 Aug 2008 19:10:48 +0200 |
parents | |
children | c4fb132a086c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/text/information/InformationPresenter.d Sat Aug 23 19:10:48 2008 +0200 @@ -0,0 +1,493 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.jface.text.information.InformationPresenter; + +import dwt.dwthelper.utils; + +import java.util.HashMap; +import java.util.Map; + +import dwt.custom.StyledText; +import dwt.events.ControlEvent; +import dwt.events.ControlListener; +import dwt.events.FocusEvent; +import dwt.events.FocusListener; +import dwt.events.KeyEvent; +import dwt.events.KeyListener; +import dwt.events.MouseEvent; +import dwt.events.MouseListener; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.widgets.Control; +import dwt.widgets.Display; +import dwtx.core.runtime.Assert; +import dwtx.jface.text.AbstractInformationControlManager; +import dwtx.jface.text.BadLocationException; +import dwtx.jface.text.IDocumentExtension3; +import dwtx.jface.text.IInformationControl; +import dwtx.jface.text.IInformationControlCreator; +import dwtx.jface.text.IRegion; +import dwtx.jface.text.ITextViewer; +import dwtx.jface.text.ITextViewerExtension5; +import dwtx.jface.text.IViewportListener; +import dwtx.jface.text.IWidgetTokenKeeper; +import dwtx.jface.text.IWidgetTokenKeeperExtension; +import dwtx.jface.text.IWidgetTokenOwner; +import dwtx.jface.text.IWidgetTokenOwnerExtension; +import dwtx.jface.text.Region; +import dwtx.jface.text.TextUtilities; + + +/** + * Standard implementation of <code>IInformationPresenter</code>. + * This implementation extends <code>AbstractInformationControlManager</code>. + * The information control is made visible on request by calling + * {@link #showInformationControl(Rectangle)}. + * <p> + * Usually, clients instantiate this class and configure it before using it. The configuration + * must be consistent: This means the used {@link dwtx.jface.text.IInformationControlCreator} + * must create an information control expecting information in the same format the configured + * {@link dwtx.jface.text.information.IInformationProvider}s use to encode the information they provide. + * </p> + * + * @since 2.0 + */ +public class InformationPresenter : AbstractInformationControlManager , IInformationPresenter, IInformationPresenterExtension, IWidgetTokenKeeper, IWidgetTokenKeeperExtension { + + + /** + * Priority of the info controls managed by this information presenter. + * Default value: <code>5</code>. + * + * @since 3.0 + */ + /* + * 5 as value has been chosen in order to beat the hovers of {@link dwtx.jface.text.TextViewerHoverManager} + */ + public static final int WIDGET_PRIORITY= 5; + + + /** + * Internal information control closer. Listens to several events issued by its subject control + * and closes the information control when necessary. + */ + class Closer : IInformationControlCloser, ControlListener, MouseListener, FocusListener, IViewportListener, KeyListener { + + /** The subject control. */ + private Control fSubjectControl; + /** The information control. */ + private IInformationControl fInformationControlToClose; + /** Indicates whether this closer is active. */ + private bool fIsActive= false; + + /* + * @see IInformationControlCloser#setSubjectControl(Control) + */ + public void setSubjectControl(Control control) { + fSubjectControl= control; + } + + /* + * @see IInformationControlCloser#setInformationControl(IInformationControl) + */ + public void setInformationControl(IInformationControl control) { + fInformationControlToClose= control; + } + + /* + * @see IInformationControlCloser#start(Rectangle) + */ + public void start(Rectangle informationArea) { + + if (fIsActive) + return; + fIsActive= true; + + if (fSubjectControl !is null && !fSubjectControl.isDisposed()) { + fSubjectControl.addControlListener(this); + fSubjectControl.addMouseListener(this); + fSubjectControl.addFocusListener(this); + fSubjectControl.addKeyListener(this); + } + + if (fInformationControlToClose !is null) + fInformationControlToClose.addFocusListener(this); + + fTextViewer.addViewportListener(this); + } + + /* + * @see IInformationControlCloser#stop() + */ + public void stop() { + + if (!fIsActive) + return; + fIsActive= false; + + fTextViewer.removeViewportListener(this); + + if (fInformationControlToClose !is null) + fInformationControlToClose.removeFocusListener(this); + + if (fSubjectControl !is null && !fSubjectControl.isDisposed()) { + fSubjectControl.removeControlListener(this); + fSubjectControl.removeMouseListener(this); + fSubjectControl.removeFocusListener(this); + fSubjectControl.removeKeyListener(this); + } + } + + /* + * @see ControlListener#controlResized(ControlEvent) + */ + public void controlResized(ControlEvent e) { + hideInformationControl(); + } + + /* + * @see ControlListener#controlMoved(ControlEvent) + */ + public void controlMoved(ControlEvent e) { + hideInformationControl(); + } + + /* + * @see MouseListener#mouseDown(MouseEvent) + */ + public void mouseDown(MouseEvent e) { + hideInformationControl(); + } + + /* + * @see MouseListener#mouseUp(MouseEvent) + */ + public void mouseUp(MouseEvent e) { + } + + /* + * @see MouseListener#mouseDoubleClick(MouseEvent) + */ + public void mouseDoubleClick(MouseEvent e) { + hideInformationControl(); + } + + /* + * @see FocusListener#focusGained(FocusEvent) + */ + public void focusGained(FocusEvent e) { + } + + /* + * @see FocusListener#focusLost(FocusEvent) + */ + public void focusLost(FocusEvent e) { + Display d= fSubjectControl.getDisplay(); + d.asyncExec(new Runnable() { + // Without the asyncExec, mouse clicks to the workbench window are swallowed. + public void run() { + if (fInformationControlToClose is null || !fInformationControlToClose.isFocusControl()) + hideInformationControl(); + } + }); + } + + /* + * @see IViewportListenerListener#viewportChanged(int) + */ + public void viewportChanged(int topIndex) { + hideInformationControl(); + } + + /* + * @see KeyListener#keyPressed(KeyEvent) + */ + public void keyPressed(KeyEvent e) { + hideInformationControl(); + } + + /* + * @see KeyListener#keyReleased(KeyEvent) + */ + public void keyReleased(KeyEvent e) { + } + } + + + /** The text viewer this information presenter works on */ + private ITextViewer fTextViewer; + /** The map of <code>IInformationProvider</code> objects */ + private Map fProviders; + /** The offset to override selection. */ + private int fOffset= -1; + /** + * The document partitioning for this information presenter. + * @since 3.0 + */ + private String fPartitioning; + + /** + * Creates a new information presenter that uses the given information control creator. + * The presenter is not installed on any text viewer yet. By default, an information + * control closer is set that closes the information control in the event of key strokes, + * resizing, moves, focus changes, mouse clicks, and disposal - all of those applied to + * the information control's parent control. Also, the setup ensures that the information + * control when made visible will request the focus. By default, the default document + * partitioning {@link IDocumentExtension3#DEFAULT_PARTITIONING} is used. + * + * @param creator the information control creator to be used + */ + public InformationPresenter(IInformationControlCreator creator) { + super(creator); + setCloser(new Closer()); + takesFocusWhenVisible(true); + fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING; + } + + /** + * Sets the document partitioning to be used by this information presenter. + * + * @param partitioning the document partitioning to be used by this information presenter + * @since 3.0 + */ + public void setDocumentPartitioning(String partitioning) { + Assert.isNotNull(partitioning); + fPartitioning= partitioning; + } + + /* + * @see dwtx.jface.text.information.IInformationPresenterExtension#getDocumentPartitioning() + * @since 3.0 + */ + public String getDocumentPartitioning() { + return fPartitioning; + } + + /** + * Registers a given information provider for a particular content type. + * If there is already a provider registered for this type, the new provider + * is registered instead of the old one. + * + * @param provider the information provider to register, or <code>null</code> to remove an existing one + * @param contentType the content type under which to register + */ + public void setInformationProvider(IInformationProvider provider, String contentType) { + + Assert.isNotNull(contentType); + + if (fProviders is null) + fProviders= new HashMap(); + + if (provider is null) + fProviders.remove(contentType); + else + fProviders.put(contentType, provider); + } + + /* + * @see IInformationPresenter#getInformationProvider(String) + */ + public IInformationProvider getInformationProvider(String contentType) { + if (fProviders is null) + return null; + + return (IInformationProvider) fProviders.get(contentType); + } + + /** + * Sets a offset to override the selection. Setting the value to <code>-1</code> will disable + * overriding. + * + * @param offset the offset to override selection or <code>-1</code> + */ + public void setOffset(int offset) { + fOffset= offset; + } + + /* + * @see AbstractInformationControlManager#computeInformation() + */ + protected void computeInformation() { + + int offset= fOffset < 0 ? fTextViewer.getSelectedRange().x : fOffset; + if (offset is -1) + return; + + fOffset= -1; + + IInformationProvider provider= null; + try { + String contentType= TextUtilities.getContentType(fTextViewer.getDocument(), getDocumentPartitioning(), offset, true); + provider= getInformationProvider(contentType); + } catch (BadLocationException x) { + } + if (provider is null) + return; + + IRegion subject= provider.getSubject(fTextViewer, offset); + if (subject is null) + return; + + Object info; + if (provider instanceof IInformationProviderExtension) { + IInformationProviderExtension extension= (IInformationProviderExtension) provider; + info= extension.getInformation2(fTextViewer, subject); + } else { + // backward compatibility code + info= provider.getInformation(fTextViewer, subject); + } + + if (provider instanceof IInformationProviderExtension2) + setCustomInformationControlCreator(((IInformationProviderExtension2) provider).getInformationPresenterControlCreator()); + else + setCustomInformationControlCreator(null); + + setInformation(info, computeArea(subject)); + } + + /** + * Determines the graphical area covered by the given text region. + * + * @param region the region whose graphical extend must be computed + * @return the graphical extend of the given region + */ + private Rectangle computeArea(IRegion region) { + + int start= 0; + int end= 0; + + IRegion widgetRegion= modelRange2WidgetRange(region); + if (widgetRegion !is null) { + start= widgetRegion.getOffset(); + end= widgetRegion.getOffset() + widgetRegion.getLength(); + } + + StyledText styledText= fTextViewer.getTextWidget(); + Rectangle bounds; + if (end > 0 && start < end) + bounds= styledText.getTextBounds(start, end - 1); + else { + Point loc= styledText.getLocationAtOffset(start); + bounds= new Rectangle(loc.x, loc.y, 0, styledText.getLineHeight(start)); + } + + return bounds; + } + + /** + * Translated the given range in the viewer's document into the corresponding + * range of the viewer's widget. + * + * @param region the range in the viewer's document + * @return the corresponding widget range + * @since 2.1 + */ + private IRegion modelRange2WidgetRange(IRegion region) { + if (fTextViewer instanceof ITextViewerExtension5) { + ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; + return extension.modelRange2WidgetRange(region); + } + + IRegion visibleRegion= fTextViewer.getVisibleRegion(); + int start= region.getOffset() - visibleRegion.getOffset(); + int end= start + region.getLength(); + if (end > visibleRegion.getLength()) + end= visibleRegion.getLength(); + + return new Region(start, end - start); + } + + /* + * @see IInformationPresenter#install(ITextViewer) + */ + public void install(ITextViewer textViewer) { + fTextViewer= textViewer; + install(fTextViewer.getTextWidget()); + } + + /* + * @see IInformationPresenter#uninstall() + */ + public void uninstall() { + dispose(); + } + + /* + * @see AbstractInformationControlManager#showInformationControl(Rectangle) + */ + protected void showInformationControl(Rectangle subjectArea) { + if (fTextViewer instanceof IWidgetTokenOwnerExtension && fTextViewer instanceof IWidgetTokenOwner) { + IWidgetTokenOwnerExtension extension= (IWidgetTokenOwnerExtension) fTextViewer; + if (extension.requestWidgetToken(this, WIDGET_PRIORITY)) + super.showInformationControl(subjectArea); + } else if (fTextViewer instanceof IWidgetTokenOwner) { + IWidgetTokenOwner owner= (IWidgetTokenOwner) fTextViewer; + if (owner.requestWidgetToken(this)) + super.showInformationControl(subjectArea); + + } else + super.showInformationControl(subjectArea); + } + + /* + * @see AbstractInformationControlManager#hideInformationControl() + */ + protected void hideInformationControl() { + try { + super.hideInformationControl(); + } finally { + if (fTextViewer instanceof IWidgetTokenOwner) { + IWidgetTokenOwner owner= (IWidgetTokenOwner) fTextViewer; + owner.releaseWidgetToken(this); + } + } + } + + /* + * @see AbstractInformationControlManager#handleInformationControlDisposed() + */ + protected void handleInformationControlDisposed() { + try { + super.handleInformationControlDisposed(); + } finally { + if (fTextViewer instanceof IWidgetTokenOwner) { + IWidgetTokenOwner owner= (IWidgetTokenOwner) fTextViewer; + owner.releaseWidgetToken(this); + } + } + } + + /* + * @see dwtx.jface.text.IWidgetTokenKeeper#requestWidgetToken(IWidgetTokenOwner) + */ + public bool requestWidgetToken(IWidgetTokenOwner owner) { + return false; + } + + /* + * @see dwtx.jface.text.IWidgetTokenKeeperExtension#requestWidgetToken(dwtx.jface.text.IWidgetTokenOwner, int) + * @since 3.0 + */ + public bool requestWidgetToken(IWidgetTokenOwner owner, int priority) { + return false; + } + + /* + * @see dwtx.jface.text.IWidgetTokenKeeperExtension#setFocus(dwtx.jface.text.IWidgetTokenOwner) + * @since 3.0 + */ + public bool setFocus(IWidgetTokenOwner owner) { + return false; + } +} +