/* * $Id$ * * Copyright (c) 2006 by the TeXlipse team. * 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 */ package net.sourceforge.texlipse.editor.hover; import net.sourceforge.texlipse.TexlipsePlugin; import net.sourceforge.texlipse.editor.TexEditor; import net.sourceforge.texlipse.model.AbstractEntry; import net.sourceforge.texlipse.model.ReferenceEntry; import net.sourceforge.texlipse.model.ReferenceManager; import net.sourceforge.texlipse.model.TexCommandEntry; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlExtension; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; 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.Shell; /** * This class creates a informative hover for commands and BibTex entries. * * @author Boris von Loesch * @author Oskar Ojala */ public class TexInformationControl implements IInformationControl, IInformationControlExtension { private AbstractEntry entry = null; private ReferenceManager refMana; private IDocument document; private TexEditor editor; private Image image; private Composite imageComposite; private Composite textComposite; private Shell shell; private int maxWidth; // private int maxHeight; private Display display; private boolean hasImage = false; // private ScrolledFormText hoverText; private StyledText hoverText; public TexInformationControl(TexEditor editor, Shell container) { this.editor = editor; document = editor.getTexDocument(); refMana = editor.getDocumentModel().getRefMana(); shell = new Shell(container, SWT.NO_FOCUS | SWT.ON_TOP | SWT.MODELESS); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 3; layout.marginWidth = 3; shell.setLayout(layout); display = shell.getDisplay(); shell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); } /** * Creates a composite with a ScrolledFormText to display the info text */ private void initTextBox() { textComposite = new Composite(shell, SWT.NONE); textComposite.setLayout(new FillLayout()); GridData gdata = new GridData(SWT.FILL, SWT.TOP, true, false); textComposite.setLayoutData(gdata); hoverText = new StyledText(textComposite, SWT.WRAP); hoverText.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); } /** * Creates a composites which contains an image of the command */ private void createImageComp() { this.imageComposite = new Composite(shell, SWT.NONE); imageComposite.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); imageComposite.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { try { GC gc = e.gc; gc.drawRectangle(0, 0, e.width - 1, e.height - 1); if (hasImage) { gc.drawImage(image, 2, 2); } } catch (Exception ex) { TexlipsePlugin.log("TexInformationControl: ", ex); } } }); GridData data = new GridData(); data.grabExcessHorizontalSpace = false; data.grabExcessVerticalSpace = false; data.verticalAlignment = SWT.TOP; if (image != null) { data.widthHint = image.getBounds().width + 4; data.heightHint = image.getBounds().height + 4; } imageComposite.setLayoutData(data); imageComposite.pack(); } /** * Set the text of the ScrolledFormText for a command help * * @param text */ private void setCommandText(String text) { StyleRange bold = new StyleRange(); bold.fontStyle = SWT.BOLD; int endLine = text.indexOf('\n'); int endBold = endLine >= 0 ? endLine : text.length(); hoverText.append(text.substring(0, endBold)); bold.start = 0; bold.length = endBold; hoverText.setStyleRange(bold); if (endLine >= 0) { hoverText.append(text.substring(endLine)); } } /** * Retrieves the argument from the given string containing * a full TeX command * * @param text The TeX command * @return The argument without braces */ private static String getArgument(String text) { int begin = text.indexOf('{'); int end = text.indexOf('}'); // "{" has to be to the first character of the text if (begin > -1 && end > begin) { return text.substring(begin + 1, end); } return ""; } /** * Retrieves the command from the given string containing * a full TeX command * * @param text The TeX command in the form <code>command{arg}</code> * @return <code>command</code> */ private static String getCommand(String text) { int begin = text.indexOf('{'); if (begin > -1) { return text.substring(0, begin); } return text; } /** * Sets the hover for a reference to a BibTeX entry * * @param ref The reference */ private void setBibHover(String ref) { ReferenceEntry bibentry = refMana.getBib(ref); if (bibentry != null) { entry = bibentry; initTextBox(); hoverText.setText(bibentry.info); } } /** * Sets the hover for a reference to a label * * @param labelName The name of the label that's referred to * @return true, if label exist */ private boolean setRefHover(String labelName) { ReferenceEntry label = refMana.getLabel(labelName); if (label != null) { entry = label; initTextBox(); hoverText.setText(label.info); return true; } return false; } /* (non-Javadoc) * @see org.eclipse.jface.text.IInformationControl#setInformation(java.lang.String) */ public void setInformation(String information) { entry = null; hasImage = false; // Only processing of commands if (information.startsWith("\\")) { String command = information.substring(1); if (command.indexOf("ref") > -1 && command.indexOf("{") > -1) { if (!setRefHover(getArgument(command))) return; } else { TexCommandEntry comEntries = refMana.getEntry(getCommand(command)); if (comEntries != null) { entry = comEntries; if (comEntries.imageDesc != null) { hasImage = true; image = comEntries.getImage(); createImageComp(); } initTextBox(); if (comEntries.info != null) { setCommandText(comEntries.info); } } else return; } shell.pack(); int w = shell.getSize().x; int h = shell.getSize().y; int fontHeight = hoverText.getFont().getFontData()[0].getHeight() + 2; if (w > maxWidth) { int plus = (h * w) / maxWidth - h; if (plus % fontHeight != 0) plus = (plus / fontHeight + 1) * fontHeight; h += plus; w = maxWidth; } shell.setSize(w, h); shell.layout(); } else { // if there's just text, then it's a bibtex-entry setBibHover(information.trim()); } } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setSizeConstraints(int, * int) */ public void setSizeConstraints(int maxWidth, int maxHeight) { // this.maxHeight = maxHeight; this.maxWidth = maxWidth; /* * shell.setSize(maxWidth, maxHeight); shell.layout(); */ } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#computeSizeHint() */ public Point computeSizeHint() { if (entry != null) { return shell.getSize(); } return shell.computeSize(SWT.DEFAULT, SWT.DEFAULT); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setVisible(boolean) */ public void setVisible(boolean visible) { shell.setVisible(visible); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setSize(int, int) */ public void setSize(int width, int height) { shell.setSize(width, height); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setLocation(org.eclipse.swt.graphics.Point) */ public void setLocation(Point location) { shell.setLocation(location); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#dispose() */ public void dispose() { shell.dispose(); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#addDisposeListener(org.eclipse.swt.events.DisposeListener) */ public void addDisposeListener(DisposeListener listener) { shell.addDisposeListener(listener); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#removeDisposeListener(org.eclipse.swt.events.DisposeListener) */ public void removeDisposeListener(DisposeListener listener) { shell.removeDisposeListener(listener); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setForegroundColor(org.eclipse.swt.graphics.Color) */ public void setForegroundColor(Color foreground) { hoverText.setForeground(foreground); shell.setForeground(foreground); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setBackgroundColor(org.eclipse.swt.graphics.Color) */ public void setBackgroundColor(Color background) { hoverText.setBackground(background); shell.setBackground(background); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#isFocusControl() */ public boolean isFocusControl() { if (!hasImage) return true; return false; } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#setFocus() */ public void setFocus() { if (!hasImage) { shell.forceFocus(); hoverText.setFocus(); } } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#addFocusListener(org.eclipse.swt.events.FocusListener) */ public void addFocusListener(FocusListener listener) { shell.addFocusListener(listener); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControl#removeFocusListener(org.eclipse.swt.events.FocusListener) */ public void removeFocusListener(FocusListener listener) { shell.removeFocusListener(listener); } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IInformationControlExtension#hasContents() */ public boolean hasContents() { if (entry == null) return false; return true; } }