/*
* Copyright (c) 2011, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.ui.internal.text.functions;
import com.google.dart.tools.ui.internal.text.dart.hover.SourceViewerInformationControl;
import com.google.dart.tools.ui.text.DartPartitions;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
/**
* Specialized source viewer information control used to display quick diff hovers.
*/
class ChangeHoverInformationControl extends SourceViewerInformationControl {
/** The font name for the viewer font - the same as the java editor's. */
private static final String SYMBOLIC_FONT_NAME = "com.google.dart.tools.ui.editors.textfont"; //$NON-NLS-1$
/**
* The maximum width of the control, set in <code>setSizeConstraints(int, int)</code>.
*/
int fMaxWidth = Integer.MAX_VALUE;
/**
* The maximum height of the control, set in <code>setSizeConstraints(int, int)</code>.
*/
int fMaxHeight = Integer.MAX_VALUE;
/**
* The partition type to be used as the starting partition type by the partition scanner.
*/
private String fPartition;
/** The horizontal scroll index. */
private int fHorizontalScrollPixel;
/**
* Creates a new information control.
*
* @param parent the shell that is the parent of this hover / control
* @param shellStyle the additional styles for the shell
* @param style the additional styles for the styled text widget
* @param partition the initial partition type to be used for the underlying viewer
* @param statusFieldText the text to be used in the optional status field or <code>null</code> if
* the status field should be hidden
*/
public ChangeHoverInformationControl(Shell parent, int shellStyle, int style, String partition,
String statusFieldText) {
super(parent, shellStyle, style, statusFieldText);
setViewerFont();
setStartingPartitionType(partition);
}
/*
* @see org.eclipse.jface.text.IInformationControl#computeSizeHint()
*/
@Override
public Point computeSizeHint() {
Point size = super.computeSizeHint();
size.x = Math.min(size.x, fMaxWidth);
size.y = Math.min(size.y, fMaxHeight);
return size;
}
/*
* @see com.google.dart.tools.ui.functions.java.hover.SourceViewerInformationControl
* #hasContents()
*/
@Override
public boolean hasContents() {
return super.hasContents() && fMaxWidth > 0;
}
/**
* Sets the horizontal scroll index in pixels.
*
* @param scrollIndex the new horizontal scroll index
*/
public void setHorizontalScrollPixel(int scrollIndex) {
scrollIndex = Math.max(0, scrollIndex);
fHorizontalScrollPixel = scrollIndex;
}
/*
* @see org.eclipse.jface.text.IInformationControl#setInformation(java.lang.String)
*/
@Override
public void setInformation(String content) {
super.setInformation(content);
IDocument doc = getViewer().getDocument();
if (doc == null) {
return;
}
// ensure that we can scroll enough
ensureScrollable();
String start = null;
if (DartPartitions.DART_DOC.equals(fPartition)) {
start = "/**" + doc.getLegalLineDelimiters()[0]; //$NON-NLS-1$
} else if (DartPartitions.DART_MULTI_LINE_COMMENT.equals(fPartition)) {
start = "/*" + doc.getLegalLineDelimiters()[0]; //$NON-NLS-1$
}
if (start != null) {
try {
doc.replace(0, 0, start);
int startLen = start.length();
getViewer().setDocument(doc, startLen, doc.getLength() - startLen);
} catch (BadLocationException e) {
// impossible
Assert.isTrue(false);
}
}
getViewer().getTextWidget().setHorizontalPixel(fHorizontalScrollPixel);
}
/*
* @see org.eclipse.jface.text.IInformationControl#setSizeConstraints(int, int)
*/
@Override
public void setSizeConstraints(int maxWidth, int maxHeight) {
fMaxWidth = maxWidth;
fMaxHeight = maxHeight;
}
/**
* Sets the initial partition for the underlying source viewer.
*
* @param partition the partition type
*/
public void setStartingPartitionType(String partition) {
if (partition == null) {
fPartition = IDocument.DEFAULT_CONTENT_TYPE;
} else {
fPartition = partition;
}
}
/**
* Ensures that the control can be scrolled at least to <code>fHorizontalScrollPixel</code> and
* adjusts <code>fMaxWidth</code> accordingly.
*/
private void ensureScrollable() {
IDocument doc = getViewer().getDocument();
if (doc == null) {
return;
}
StyledText widget = getViewer().getTextWidget();
if (widget == null || widget.isDisposed()) {
return;
}
int last = doc.getNumberOfLines() - 1;
GC gc = new GC(widget);
gc.setFont(widget.getFont());
int maxWidth = 0;
String content = new String();
try {
for (int i = 0; i <= last; i++) {
IRegion line;
line = doc.getLineInformation(i);
content = doc.get(line.getOffset(), line.getLength());
int width = gc.textExtent(content).x;
if (width > maxWidth) {
maxWidth = width;
}
}
} catch (BadLocationException e) {
return;
} finally {
gc.dispose();
}
// limit the size of the window to the maximum width minus scrolling,
// but never more than the configured max size (viewport size).
fMaxWidth = Math.max(0, Math.min(fMaxWidth, maxWidth - fHorizontalScrollPixel + 8));
}
/**
* Sets the font for this viewer sustaining selection and scroll position.
*/
private void setViewerFont() {
Font font = JFaceResources.getFont(SYMBOLIC_FONT_NAME);
if (getViewer().getDocument() != null) {
Point selection = getViewer().getSelectedRange();
int topIndex = getViewer().getTopIndex();
StyledText styledText = getViewer().getTextWidget();
Control parent = styledText;
if (getViewer() instanceof ITextViewerExtension) {
ITextViewerExtension extension = (ITextViewerExtension) getViewer();
parent = extension.getControl();
}
parent.setRedraw(false);
styledText.setFont(font);
getViewer().setSelectedRange(selection.x, selection.y);
getViewer().setTopIndex(topIndex);
if (parent instanceof Composite) {
Composite composite = (Composite) parent;
composite.layout(true);
}
parent.setRedraw(true);
} else {
StyledText styledText = getViewer().getTextWidget();
styledText.setFont(font);
}
}
}