Initial commit from SVN.
This commit is contained in:
268
Snippets/src/org/eclipse/swt/graphics/StyledDocument.java
Normal file
268
Snippets/src/org/eclipse/swt/graphics/StyledDocument.java
Normal file
@@ -0,0 +1,268 @@
|
||||
package org.eclipse.swt.graphics;
|
||||
|
||||
import org.eclipse.swt.*;
|
||||
import org.eclipse.swt.custom.*;
|
||||
import org.eclipse.swt.events.*;
|
||||
import org.eclipse.swt.graphics.*;
|
||||
import org.eclipse.swt.layout.*;
|
||||
import org.eclipse.swt.widgets.*;
|
||||
|
||||
import com.common.util.LiteHashMap;
|
||||
import com.common.util.LiteList;
|
||||
import com.common.util.optimized.IntObjectHashMap;
|
||||
|
||||
/**
|
||||
* <pre>Attempt at writing an SWT document display that allows:
|
||||
* word wrap or no word wrap
|
||||
* document within document
|
||||
* images with text wrap & attached to top, bottom, or text position (center, left, right align?)
|
||||
* hyperlinks
|
||||
* other controls (maybe just panel?)</pre>
|
||||
*/
|
||||
public class StyledDocument extends Canvas {
|
||||
public static final int LEFT_WRAPPED = 0;
|
||||
public static final int RIGHT_WRAPPED = 1;
|
||||
public static final int UNWRAPPED = 2;
|
||||
|
||||
private int width = 0;
|
||||
private String text = null;
|
||||
private String[] paragraphs = null;
|
||||
/** Assumes currently that the images are ordered first by paragraph #, then by VALIGN (TOP, then BOTTOM), then by HALIGN (HALIGN_LEFT, HALIGN_CENTER, HALIGN_RIGHT, HALIGN_LEFT_WRAPPED, then HALIGN_RIGHT_WRAPPED). */
|
||||
private ParagraphContainer[] paragraphContainers = null;
|
||||
/** Whether the metadata on the content has been reset, requiring a re-layout of the text. */
|
||||
private boolean isReset = true;
|
||||
|
||||
private static class DocumentPart {
|
||||
public TextLayout partLayout = null;
|
||||
public int lineCount = 0;
|
||||
}//DocumentPart//
|
||||
|
||||
private static class ComponentPart {
|
||||
public Image image = null;
|
||||
public Control control = null;
|
||||
/** The orientation of the component part, either LEFT_WRAPPED, RIGHT_WRAPPED, or UNWRAPPED (if it is the top component). */
|
||||
public int orientation = LEFT_WRAPPED;
|
||||
public int leftPadding = 0;
|
||||
public int rightPadding = 0;
|
||||
public int topPadding = 0;
|
||||
public int bottomPadding = 0;
|
||||
/** Only used with wrapped parts. Determines how far from the preceeding component part or paragraph top before text starts wrapping and the component appears. */
|
||||
public int offset = 0;
|
||||
}//ComponentPart//
|
||||
|
||||
private static class ParagraphContainer {
|
||||
/** A collection of TextLayout instances used in a previous rendering. */
|
||||
public LiteList layouts = new LiteList(1, 10);
|
||||
public ComponentPart top = null;
|
||||
public LiteList left = null;
|
||||
public LiteList right = null;
|
||||
|
||||
public void reset() {
|
||||
for(int index = layouts.getSize() - 1; index >= 0; index--) {
|
||||
((TextLayout) layouts.remove(index)).dispose();
|
||||
}//for//
|
||||
}//reset()//
|
||||
}//ParagraphContainer//
|
||||
/**
|
||||
* StyledDocument constructor.
|
||||
* @param parent
|
||||
* @param style
|
||||
*/
|
||||
public StyledDocument(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
|
||||
addPaintListener(new PaintListener() {
|
||||
public void paintControl(PaintEvent e) {
|
||||
organize();
|
||||
}
|
||||
});
|
||||
|
||||
addControlListener(new ControlListener() {
|
||||
public void controlResized(ControlEvent e) {
|
||||
width = getSize().x;
|
||||
reset();
|
||||
}
|
||||
public void controlMoved(ControlEvent e) {
|
||||
}
|
||||
});
|
||||
}//StyledDocument()//
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void organize() {
|
||||
//If the control has been reset then re-layout the text.//
|
||||
if(isReset) {
|
||||
//Iterate over the paragraphs, processing them one at a time.//
|
||||
for(int paragraphIndex = 0; paragraphIndex < paragraphs.length; paragraphIndex++) {
|
||||
String subText = paragraphs[paragraphIndex];
|
||||
ParagraphContainer container = paragraphContainers[paragraphIndex];
|
||||
|
||||
if(container.left == null && container.right == null) {
|
||||
TextLayout textLayout = new TextLayout(getDisplay());
|
||||
|
||||
textLayout.setText(subText);
|
||||
container.layouts.add(textLayout);
|
||||
}//if//
|
||||
else {
|
||||
ComponentPart nextLeft = null;
|
||||
ComponentPart nextRight = null;
|
||||
|
||||
while(subText != null) {
|
||||
TextLayout textLayout = new TextLayout(getDisplay());
|
||||
int lineIndex = 0;
|
||||
int height = 0;
|
||||
Rectangle lineBounds;
|
||||
|
||||
textLayout.setText(subText);
|
||||
textLayout.setWidth(width);
|
||||
lineBounds = textLayout.getLineBounds(lineIndex);
|
||||
height += lineBounds.height;
|
||||
|
||||
while(height)
|
||||
|
||||
textLayout.draw(e.gc, 0, 0);
|
||||
}//while//
|
||||
}//else//
|
||||
}//for//
|
||||
|
||||
isReset = false;
|
||||
}//if//
|
||||
}//organize()//
|
||||
/**
|
||||
* Adds a control to the document.
|
||||
* @param paragraphIndex The index of the paragraph the control is attached to.
|
||||
* @param orientation The orientation of the control relative to the paragraph.
|
||||
* @param control The control being added.
|
||||
* @param topPadding The padding above the control that text will not exist in.
|
||||
* @param rightPadding The padding right of the control that text will not exist in.
|
||||
* @param bottomPadding The padding below the control that text will not exist in.
|
||||
* @param leftPadding The padding left of the control that text will not exist in.
|
||||
* @param offset The offset between the control and the previous control/image or top of the paragraph that text can exist within. This does not include padding, and is ignored if the orientation is UNWRAPPED.
|
||||
*/
|
||||
public void addControl(int paragraphIndex, int orientation, Control control, int topPadding, int rightPadding, int bottomPadding, int leftPadding, int offset) {
|
||||
add(paragraphIndex, orientation, control, topPadding, rightPadding, bottomPadding, leftPadding, offset);
|
||||
}//addControl()//
|
||||
/**
|
||||
* Adds an image to the document.
|
||||
* @param paragraphIndex The index of the paragraph the image is attached to.
|
||||
* @param orientation The orientation of the image relative to the paragraph.
|
||||
* @param control The image being added.
|
||||
* @param topPadding The padding above the image that text will not exist in.
|
||||
* @param rightPadding The padding right of the image that text will not exist in.
|
||||
* @param bottomPadding The padding below the image that text will not exist in.
|
||||
* @param leftPadding The padding left of the image that text will not exist in.
|
||||
* @param offset The offset between the image and the previous control/image or top of the paragraph that text can exist within. This does not include padding, and is ignored if the orientation is UNWRAPPED.
|
||||
*/
|
||||
public void addImage(int paragraphIndex, int orientation, Image image, int topPadding, int rightPadding, int bottomPadding, int leftPadding, int offset) {
|
||||
add(paragraphIndex, orientation, image, topPadding, rightPadding, bottomPadding, leftPadding, offset);
|
||||
}//addImage()//
|
||||
private void add(int paragraphIndex, int orientation, Object controlOrImage, int topPadding, int rightPadding, int bottomPadding, int leftPadding, int offset) {
|
||||
if(paragraphIndex >= 0 && paragraphIndex < paragraphContainers.length) {
|
||||
ParagraphContainer container = paragraphContainers[paragraphIndex];
|
||||
ComponentPart part = new ComponentPart();
|
||||
|
||||
if(controlOrImage instanceof Image) {
|
||||
part.image = (Image) controlOrImage;
|
||||
}//if//
|
||||
else if(controlOrImage instanceof Control) {
|
||||
part.control = (Control) controlOrImage;
|
||||
}//else if//
|
||||
|
||||
part.topPadding = topPadding;
|
||||
part.rightPadding = rightPadding;
|
||||
part.bottomPadding = bottomPadding;
|
||||
part.leftPadding = leftPadding;
|
||||
|
||||
switch(orientation) {
|
||||
case UNWRAPPED: {
|
||||
if(container.top == null) {
|
||||
container.top = part;
|
||||
}//if//
|
||||
else {
|
||||
throw new RuntimeException("Cannot have multiple top components.");
|
||||
}//else//
|
||||
break;
|
||||
}//case//
|
||||
case RIGHT_WRAPPED: {
|
||||
if(container.right == null) {
|
||||
container.right = new LiteList(3, 10);
|
||||
}//if//
|
||||
|
||||
container.right.add(part);
|
||||
break;
|
||||
}//case//
|
||||
case LEFT_WRAPPED: {
|
||||
if(container.left == null) {
|
||||
container.left = new LiteList(3, 10);
|
||||
}//if//
|
||||
|
||||
container.left.add(part);
|
||||
break;
|
||||
}//case//
|
||||
}//switch//
|
||||
}//if//
|
||||
else {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}//else//
|
||||
}//add()//
|
||||
/**
|
||||
* Sets the text, reseting the entire control.
|
||||
* @param text The initial text for the control.
|
||||
*/
|
||||
public void setText(String text) {
|
||||
text = text.replace("\r\n", "\n");
|
||||
|
||||
if(!text.equals(this.text)) {
|
||||
this.text = text;
|
||||
this.paragraphs = this.text.split("\n");
|
||||
|
||||
//TODO: Should we remove empty paragraphs?
|
||||
|
||||
//Cleanup old metadata.//
|
||||
reset();
|
||||
//Create a new metadata container.//
|
||||
this.paragraphContainers = new ParagraphContainer[paragraphs.length];
|
||||
|
||||
//Setup new metadata.//
|
||||
for(int index = 0; index < this.paragraphContainers.length; index++) {
|
||||
this.paragraphContainers[index] = new ParagraphContainer();
|
||||
}//for//
|
||||
}//if//
|
||||
}//setText()//
|
||||
/**
|
||||
* Resets the control by clearing any cached display data.
|
||||
*/
|
||||
public void reset() {
|
||||
//Cleanup old metadata.//
|
||||
if(this.paragraphContainers != null) {
|
||||
for(int index = 0; index < this.paragraphContainers.length; index++) {
|
||||
this.paragraphContainers[index].reset();
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
isReset = true;
|
||||
}//reset()//
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.swt.widgets.Widget#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
reset();
|
||||
super.dispose();
|
||||
}//dispose()//
|
||||
public static void main(String[] args) {
|
||||
final Display display = new Display();
|
||||
final Shell shell = new Shell(display);
|
||||
StyledDocument doc = null;
|
||||
|
||||
shell.setLayout(new FillLayout());
|
||||
doc = new StyledDocument(shell, SWT.WRAP | SWT.BORDER);
|
||||
|
||||
shell.setSize(400, 400);
|
||||
shell.open();
|
||||
while (!shell.isDisposed()) {
|
||||
if (!display.readAndDispatch())
|
||||
display.sleep();
|
||||
}
|
||||
display.dispose();
|
||||
}
|
||||
}//StyledDocument//
|
||||
Reference in New Issue
Block a user