| author | Stephan Schwiebert | 2011-08-23 08:37:27 (EDT) |
|---|---|---|
| committer | Fabian Steeg | 2011-08-23 08:50:16 (EDT) |
| commit | e3dcdbe6492220de5280053a816e2fbc959c4397 (patch) (side-by-side diff) | |
| tree | fd285150becd6a020a556aac8474b657e7de208a | |
| parent | e2e52cb7997cfe469d0f3cbcc8292ccadaef597c (diff) | |
| download | org.eclipse.gef4-e3dcdbe6492220de5280053a816e2fbc959c4397.zip org.eclipse.gef4-e3dcdbe6492220de5280053a816e2fbc959c4397.tar.gz org.eclipse.gef4-e3dcdbe6492220de5280053a816e2fbc959c4397.tar.bz2 | |
71 files changed, 6151 insertions, 3 deletions
diff --git a/org.eclipse.zest.cloudio/.classpath b/org.eclipse.zest.cloudio/.classpath new file mode 100644 index 0000000..fbb14bd --- a/dev/null +++ b/org.eclipse.zest.cloudio/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.zest.cloudio/.project b/org.eclipse.zest.cloudio/.project new file mode 100644 index 0000000..13e1680 --- a/dev/null +++ b/org.eclipse.zest.cloudio/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.zest.cloudio</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/org.eclipse.zest.cloudio/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.zest.cloudio/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..959127e --- a/dev/null +++ b/org.eclipse.zest.cloudio/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu Jun 02 21:00:19 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.eclipse.zest.cloudio/META-INF/MANIFEST.MF b/org.eclipse.zest.cloudio/META-INF/MANIFEST.MF new file mode 100644 index 0000000..d633766 --- a/dev/null +++ b/org.eclipse.zest.cloudio/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Cloudio UI +Bundle-SymbolicName: org.eclipse.zest.cloudio;singleton:=true +Bundle-Version: 2.0.0.qualifier +Bundle-Activator: org.eclipse.zest.cloudio.Activator +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.eclipse.zest.cloudio, + org.eclipse.zest.cloudio.layout, + org.eclipse.zest.cloudio.util diff --git a/org.eclipse.zest.cloudio/build.properties b/org.eclipse.zest.cloudio/build.properties new file mode 100644 index 0000000..23920ae --- a/dev/null +++ b/org.eclipse.zest.cloudio/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + img/ diff --git a/org.eclipse.zest.cloudio/cloudio.target b/org.eclipse.zest.cloudio/cloudio.target new file mode 100644 index 0000000..2c9f2d4 --- a/dev/null +++ b/org.eclipse.zest.cloudio/cloudio.target @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?pde version="3.6"?> + +<target includeMode="feature" name="Eclipse36"> +<locations> +<location includeAllPlatforms="true" includeMode="slicer" type="InstallableUnit"> +<unit id="org.eclipse.rcp.feature.group" version="3.6.2.r362_v20101104-9SAxFMKFkSAqi8axkv1ZjegmiBLY"/> +<repository location="http://download.eclipse.org/eclipse/updates/3.6"/> +</location> +</locations> +</target> diff --git a/org.eclipse.zest.cloudio/img/add.gif b/org.eclipse.zest.cloudio/img/add.gif Binary files differnew file mode 100644 index 0000000..252d7eb --- a/dev/null +++ b/org.eclipse.zest.cloudio/img/add.gif diff --git a/org.eclipse.zest.cloudio/img/remove.gif b/org.eclipse.zest.cloudio/img/remove.gif Binary files differnew file mode 100644 index 0000000..b6922ac --- a/dev/null +++ b/org.eclipse.zest.cloudio/img/remove.gif diff --git a/org.eclipse.zest.cloudio/img/toggle_colors.gif b/org.eclipse.zest.cloudio/img/toggle_colors.gif Binary files differnew file mode 100644 index 0000000..e3a7cc7 --- a/dev/null +++ b/org.eclipse.zest.cloudio/img/toggle_colors.gif diff --git a/org.eclipse.zest.cloudio/pom.xml b/org.eclipse.zest.cloudio/pom.xml new file mode 100644 index 0000000..fa0e6ab --- a/dev/null +++ b/org.eclipse.zest.cloudio/pom.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>org.eclipse.zest</artifactId> + <groupId>org.eclipse</groupId> + <version>2.0.0-SNAPSHOT</version> + </parent> + <groupId>org.eclipse</groupId> + <artifactId>org.eclipse.zest.cloudio</artifactId> + <version>2.0.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <version>1.3</version> + <executions> + <execution> + <id>attach-artifacts</id> + <phase>package</phase> + <goals> + <goal>attach-artifact</goal> + </goals> + <configuration> + <artifacts> + <artifact> + <file>cloudio.target</file> + <type>target</type> + <classifier>cloudio</classifier> + </artifact> + </artifacts> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>${tycho.groupId}</groupId> + <artifactId>tycho-source-plugin</artifactId> + </plugin> + </plugins> + </build> +</project> diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/Activator.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/Activator.java new file mode 100644 index 0000000..7fd45b0 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/Activator.java @@ -0,0 +1,87 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; + +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + + +/** + * + * @author sschwieb + * + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.schwiebert.eclipsetagcloud"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + + public static final String ADD = "add.gif"; + + public static final String REMOVE = "remove.gif"; + + public static final String TOGGLE_COLORS = "toggle_colors.gif"; + + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + ImageLoader il = new ImageLoader(); + loadImage(il, ADD); + loadImage(il, REMOVE); + loadImage(il, TOGGLE_COLORS); + } + + private void loadImage(ImageLoader il, String fileName) throws IOException { + InputStream stream = getBundle().getResource("img/"+fileName).openStream(); + ImageData[] data = il.load(stream); + Image image = new Image(Display.getDefault(), data[0]); + getImageRegistry().put(fileName, image); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/CloudOptionsComposite.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/CloudOptionsComposite.java new file mode 100644 index 0000000..9aeddb6 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/CloudOptionsComposite.java @@ -0,0 +1,516 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.FontDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; + +/** + * Provides options to modify the rendering of a {@link TagCloudViewer} using an + * {@link IEditableCloudLabelProvider}. + * + * @author sschwieb + * + */ +public class CloudOptionsComposite extends Composite { + + protected TagCloudViewer viewer; + + protected List<RGB> colors = new ArrayList<RGB>(); + protected List<FontData> fonts = new ArrayList<FontData>(); + + protected List<List<RGB>> colorSchemes = new ArrayList<List<RGB>>(); + + protected int currentScheme; + + private static class ListContentProvider implements ITreeContentProvider { + + @Override + public void dispose() {} + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {} + + @Override + public Object[] getElements(Object inputElement) { + return ((List<?>)inputElement).toArray(); + } + + @Override + public Object[] getChildren(Object parentElement) { + return null; + } + + @Override + public Object getParent(Object element) { + return null; + } + + @Override + public boolean hasChildren(Object element) { + return false; + } + + } + + public CloudOptionsComposite(Composite parent, int style, TagCloudViewer viewer) { + super(parent, style); + Assert.isLegal(viewer.getLabelProvider() instanceof IEditableCloudLabelProvider, "Cloud label provider must be of type " + IEditableCloudLabelProvider.class); + this.viewer = viewer; + setLayout(new GridLayout()); + addGroups(); + } + + protected void addGroups() { + addLayoutButtons(this); + addColorButtons(this); + addFontButtons(this); + } + + protected void addScheme(RGB...rgbs) { + List<RGB> colors = new ArrayList<RGB>(); + for (RGB rgb : rgbs) { + colors.add(rgb); + } + colorSchemes.add(colors); + } + + protected void updateColors() { + IEditableCloudLabelProvider lp = (IEditableCloudLabelProvider) viewer.getLabelProvider(); + lp.setColors(colors); + List<Word> words = viewer.getCloud().getWords(); + for (Word word : words) { + word.setColor(lp.getColor(word.data)); + } + viewer.getCloud().redrawTextLayerImage(); + } + + protected void updateFonts() { + IEditableCloudLabelProvider lp = (IEditableCloudLabelProvider) viewer.getLabelProvider(); + lp.setFonts(fonts); + } + + protected void initColors() { + addScheme(new RGB(222, 177, 17), new RGB(97, 28, 24), new RGB(102,109,17), new RGB(189, 112, 20), new RGB(111, 92, 16), new RGB(111, 32, 27)); + addScheme(new RGB(1,175,255), new RGB(57,99,213), new RGB(21,49,213), new RGB(30,125,42)); + addScheme(new RGB(255,92,93), new RGB(255,0,0), new RGB(255,41,43), new RGB(182,31,32), new RGB(153,0,0)); + addScheme(new RGB(255,157,0), new RGB(255,206,0), new RGB(40,0,159), new RGB(0,41,156)); + addScheme(new RGB(255,46,0), new RGB(255,255,14), new RGB(183, 183, 183), new RGB(122, 122, 122), new RGB(81, 81, 81), new RGB(61, 61, 61), new RGB(165, 165, 165)); + addScheme(new RGB(255,0,206), new RGB(255,220,0), new RGB(0, 255, 42)); + addScheme(new RGB(89, 79, 69), new RGB(168, 165, 126), new RGB(68, 49, 14), new RGB(86, 68, 34), new RGB(148, 141, 129), new RGB(92, 90, 41)); + addScheme(new RGB(66,71,37), new RGB(85,122,18), new RGB(117,131,49), new RGB(49,45,17)); + addScheme(new RGB(254,213,44), new RGB(255,177,10), new RGB(233,121,0), new RGB(229,109,3), new RGB(202,80,8), new RGB(129,52,7), new RGB(89,47,14)); + addScheme(new RGB(139,124,115), new RGB(91,95,129), new RGB(50,23,18), new RGB(255,251,237)); + nextColors(); + } + + protected void nextColors() { + currentScheme = (currentScheme+1)%colorSchemes.size(); + colors = colorSchemes.get(currentScheme); + } + + protected Group addFontButtons(final Composite parent) { + Group buttons = new Group(parent, SWT.SHADOW_IN); + buttons.setLayout(new GridLayout(2, false)); + buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + Label l = new Label(buttons, SWT.NONE); + l.setText("Fonts"); + GridData gd = new GridData(); + gd.horizontalSpan=2; + l.setLayoutData(gd); + final TreeViewer tv = new TreeViewer(buttons); + Composite comp = new Composite(buttons, SWT.NONE); + comp.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true)); + comp.setLayout(new RowLayout(SWT.VERTICAL)); + tv.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + ListContentProvider cp = new ListContentProvider(); + tv.setContentProvider(cp); + tv.setLabelProvider(new ColumnLabelProvider() { + + @Override + public String getText(Object element) { + FontData fd = (FontData) element; + return fd.getName(); + } + + }); + fonts.add(getFont().getFontData()[0]); + tv.setInput(fonts); + Button add = new Button(comp, SWT.FLAT); + add.setImage(Activator.getDefault().getImageRegistry().get(Activator.ADD)); + add.setToolTipText("Add font..."); + add.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + FontDialog fd = new FontDialog(parent.getShell()); + FontData fontData = fd.open(); + if(fontData != null) { + fonts.add(fontData); + tv.setInput(fonts); + updateFonts(); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + Button remove = new Button(comp, SWT.FLAT); + remove.setToolTipText("Remove selected fonts"); + remove.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + IStructuredSelection selection = (IStructuredSelection) tv.getSelection(); + fonts.removeAll(selection.toList()); + tv.setInput(fonts); + updateFonts(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + remove.setImage(Activator.getDefault().getImageRegistry().get(Activator.REMOVE)); + return buttons; + } + + protected Image createImageFromColor(RGB rgb, int size) { + Image image; + Color color = new Color(Display.getDefault(), rgb); + image = new Image(Display.getDefault(), size, size); + GC gc = new GC(image); + gc.setBackground(color); + gc.fillRoundRectangle(0, 0, size, size, 3, 3); + color.dispose(); + gc.dispose(); + return image; + } + + protected Group addColorButtons(final Composite parent) { + Group buttons = new Group(parent, SWT.SHADOW_IN); + buttons.setLayout(new GridLayout(2, false)); + buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + Label l = new Label(buttons, SWT.NONE); + l.setText("Colors"); + GridData gd = new GridData(); + gd.horizontalSpan=2; + l.setLayoutData(gd); + final TreeViewer tv = new TreeViewer(buttons); + Composite comp = new Composite(buttons, SWT.NONE); + comp.setLayout(new RowLayout(SWT.VERTICAL)); + comp.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true)); + tv.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + ListContentProvider cp = new ListContentProvider(); + tv.setContentProvider(cp); + tv.setLabelProvider(new ColumnLabelProvider() { + + private Map<Object, Image> images = new HashMap<Object, Image>(); + + @Override + public Image getImage(Object element) { + Image image = images.get(element); + if(image == null) { + RGB rgb = (RGB) element; + image = createImageFromColor(rgb, 24); + images.put(element, image); + } + return image; + } + + @Override + public void dispose() { + Collection<Image> images = this.images.values(); + for (Image image : images) { + image.dispose(); + } + this.images.clear(); + } + + }); + initColors(); + tv.setInput(colors); + Button add = new Button(comp, SWT.FLAT); + add.setImage(Activator.getDefault().getImageRegistry().get(Activator.ADD)); + add.setToolTipText("Add color..."); + add.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + ColorDialog cd = new ColorDialog(parent.getShell()); + RGB color = cd.open(); + if(color != null) { + colors.add(color); + tv.setInput(colors); + updateColors(); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + Button remove = new Button(comp, SWT.FLAT); + remove.setToolTipText("Remove selected colors"); + remove.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + IStructuredSelection selection = (IStructuredSelection) tv.getSelection(); + colors.removeAll(selection.toList()); + + tv.setInput(colors); + updateColors(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + remove.setImage(Activator.getDefault().getImageRegistry().get(Activator.REMOVE)); + Button toggle = new Button(comp, SWT.FLAT); + toggle.setToolTipText("Toggle Colors"); + toggle.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + nextColors(); + tv.setInput(colors); + updateColors(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + toggle.setImage(Activator.getDefault().getImageRegistry().get(Activator.TOGGLE_COLORS)); + + comp = new Composite(buttons, SWT.NONE); + gd = new GridData(SWT.FILL, SWT.FILL, true, false); + gd.horizontalSpan=2; + comp.setLayout(new GridLayout(2, true)); + comp.setLayoutData(gd); + final Button bg = new Button(comp, SWT.FLAT); + bg.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + bg.setText("Background"); + bg.setImage(createImageFromColor(viewer.getCloud().getBackground().getRGB(), 16)); + bg.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + ColorDialog cd = new ColorDialog(parent.getShell()); + RGB color = cd.open(); + if(color == null) return; + Color old = viewer.getCloud().getBackground(); + Color c = new Color(Display.getDefault(), color); + viewer.getCloud().setBackground(c); + old.dispose(); + viewer.getCloud().redrawTextLayerImage(); + Image oldImage = bg.getImage(); + Image newImage = createImageFromColor(color, 16); + bg.setImage(newImage); + oldImage.dispose(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + final Button sel = new Button(comp, SWT.FLAT); + sel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + sel.setText("Selection"); + sel.setImage(createImageFromColor(viewer.getCloud().getSelectionColor().getRGB(), 16)); + sel.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + ColorDialog cd = new ColorDialog(parent.getShell()); + RGB color = cd.open(); + if(color == null) return; + Color old = viewer.getCloud().getSelectionColor(); + Color c = new Color(Display.getDefault(), color); + viewer.getCloud().setSelectionColor(c); + old.dispose(); + viewer.getCloud().redrawTextLayerImage(); + Image oldImage = sel.getImage(); + Image newImage = createImageFromColor(color, 16); + sel.setImage(newImage); + oldImage.dispose(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + return buttons; + } + + protected Group addLayoutButtons(Composite parent) { + Group buttons = new Group(parent, SWT.SHADOW_IN); + buttons.setLayout(new GridLayout(2, true)); + buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + Label l = new Label(buttons, SWT.NONE); + l.setText("Number of Words"); + final Combo words = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + words.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + words.setItems(new String[] {"100","200","300","400","500","600","700","800","900","1000", "1100", "1200", "1300", "1400", "1500","1600", "1700", "1800", "1900", "2000"}); + words.select(2); + words.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = words.getItem(words.getSelectionIndex()); + viewer.setMaxWords(Integer.parseInt(item)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + l = new Label(buttons, SWT.NONE); + l.setText("Max Font Size"); + final Combo font = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + font.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + font.setItems(new String[] {"50", "100", "150", "200", "250", "300", "350", "400", "450", "500"}); + font.select(1); + font.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = font.getItem(font.getSelectionIndex()); + viewer.getCloud().setMaxFontSize(Integer.parseInt(item)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + l = new Label(buttons, SWT.NONE); + l.setText("Min Font Size"); + final Combo minFont = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + minFont.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + minFont.setItems(new String[] {"10", "15", "20", "25", "30", "35", "40", "45", "50"}); + minFont.select(1); + minFont.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = minFont.getItem(minFont.getSelectionIndex()); + viewer.getCloud().setMinFontSize(Integer.parseInt(item)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + l = new Label(buttons, SWT.NONE); + l.setText("Boost"); + final Combo boost = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + boost.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + boost.setItems(new String[] {"0", "1", "2","3","4","5","6","7","8","9","10"}); + boost.select(0); + boost.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = boost.getItem(boost.getSelectionIndex()); + viewer.setBoost(Integer.parseInt(item)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + + l = new Label(buttons, SWT.NONE); + l.setText("Boost Factor"); + final Combo boostFactor = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + boostFactor.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + boostFactor.setItems(new String[] {"1","1.5","2","2.5","3","3.5", "4", "4.5", "5"}); + boostFactor.select(0); + boostFactor.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = boostFactor.getItem(boostFactor.getSelectionIndex()); + viewer.setBoostFactor(Float.parseFloat(item)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + if(viewer.getLabelProvider() instanceof IEditableCloudLabelProvider) { + + } + + l = new Label(buttons, SWT.NONE); + l.setText("Angles"); + final Combo angles = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + angles.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + angles.setItems(new String[] {"Horizontal only", "Vertical only", "Horizontal & Vertical", "45 Degrees, mostly horizontal", "45 Degrees", "Random"}); + final List<List<Float>> anglesLists = new ArrayList<List<Float>>(); + anglesLists.add(Arrays.asList(0F)); + anglesLists.add(Arrays.asList(-90F,90F)); + anglesLists.add(Arrays.asList(0F,-90F,0F,90F)); + anglesLists.add(Arrays.asList(0F,-90F,-45F, 0F,45F, 90F,0F,0F,0F,0F)); + anglesLists.add(Arrays.asList(-90F,-45F, 0F,45F, 90F)); + List<Float> tmp = new ArrayList<Float>(); + for(int i = -90; i <= 90; i++) { + tmp.add((float) i); + } + anglesLists.add(tmp); + angles.select(0); + angles.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + int index = angles.getSelectionIndex(); + IEditableCloudLabelProvider lp = (IEditableCloudLabelProvider) viewer.getLabelProvider(); + lp.setAngles(anglesLists.get(index)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + return buttons; + } + + public List<RGB> getColors() { + return colors; + } + + public List<FontData> getFonts() { + return fonts; + } +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/ICloudLabelProvider.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/ICloudLabelProvider.java new file mode 100644 index 0000000..d3fb132 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/ICloudLabelProvider.java @@ -0,0 +1,72 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; + +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.FontData; + +/** + * Defines the label of an element within the cloud. Besides of the + * string-label, each element can be assigned a unique weight (used + * to calculate the font size of the rendered element), color, + * font and angle. + * @author sschwieb + * + */ +public interface ICloudLabelProvider extends IBaseLabelProvider { + + /** + * The label of the given element, which must not + * be <code>null</code>. + * @param element + * @return + */ + public String getLabel(Object element); + + /** + * The weight of the given element, which must be between + * 0 and 1 (inclusive). + * @param element + * @return + */ + public double getWeight(Object element); + + /** + * The {@link Color} of the given element, which must not + * be <code>null</code>. + * @param element + * @return + */ + public Color getColor(Object element); + + /** + * The {@link FontData}-array which defines the font + * of the given element. Each element must be provided + * with a unique array. Must not return <code>null</code>. + * @param element + * @return + */ + public FontData[] getFontData(Object element); + + /** + * The angle of the element, which must be between -90 and 90, inclusive. + * @param element + * @return + */ + public float getAngle(Object element); + + /** + * Return the tool tip of the element, or <code>null</code>, if none. + * @param data + * @return + */ + public String getToolTip(Object element); + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/IEditableCloudLabelProvider.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/IEditableCloudLabelProvider.java new file mode 100644 index 0000000..ced77a7 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/IEditableCloudLabelProvider.java @@ -0,0 +1,31 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; + +import java.util.List; + +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.RGB; + +/** + * An {@link IEditableCloudLabelProvider} is supported by the {@link CloudOptionsComposite}, + * such that it can be used to modify colors, fonts, and angles. + * + * @author sschwieb + * + */ +public interface IEditableCloudLabelProvider extends ICloudLabelProvider { + + public void setColors(List<RGB> colors); + + public void setFonts(List<FontData> fonts); + + public void setAngles(List<Float> list); + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/TagCloud.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/TagCloud.java new file mode 100644 index 0000000..ca9d246 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/TagCloud.java @@ -0,0 +1,1340 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.EventListener; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.MouseWheelListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Path; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.graphics.Transform; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.zest.cloudio.layout.DefaultLayouter; +import org.eclipse.zest.cloudio.layout.ILayouter; +import org.eclipse.zest.cloudio.util.RectTree; +import org.eclipse.zest.cloudio.util.SmallRect; + +/** + * + * @author sschwieb + * + */ +public class TagCloud extends Canvas { + + /** + * Minimum 'resolution' of the {@link RectTree} used for + * collision handling. + */ + private static final int RESOLUTION = 5; + + /** + * Maximum size of the {@link RectTree} used for collision + * handling. + */ + private static final int TREE_SIZE = 5120/* * 2 */; + + /** + * Draw area. + */ + private final Rectangle cloudArea = new Rectangle(0, 0, TREE_SIZE, TREE_SIZE); + + /** + * Maximum Font Size. + */ + private int maxFontSize = 100; + + private final GC gc; + + /** + * Highlight color. + */ + private Color highlightColor; + + /** + * Used to detect mousehover, -enter and -exit. + */ + private Word currentWord; + + /** + * Opacity of the rendered strings. + */ + private int opacity = 255; + /** + * Required for scroll bars + */ + private final Point origin = new Point (0, 0); + + /** + * Main image, on which all strings are rendered. + */ + private Image textLayerImage; + + /** + * Second level image: All Elements plus selected elements + * in highlight color. + */ + + private Image selectionLayerImage; + + /** + * Last level image: All + selected elements, zoomed. This + * is the image which will be displayed. + */ + private Image zoomLayerImage; + + /** + * The list of words to render. + */ + private List<Word> wordsToUse; + + private boolean initialized = false; + + /** + * Current zoom factor. + */ + private double currentZoom = 1; + + /** + * The region used by the rendered words. + */ + private Region region; + + /** + * Minimum font size. + */ + private int minFontSize = 12; + + /** + * Set of selected words + */ + private Set<Word> selection = new HashSet<Word>(); + + private short[][] cloudMatrix; + + /** + * Executor service to process the creation of {@link RectTree} objects + * in parallel. + */ + private ExecutorService executors; + + private ILayouter layouter; + + /** + * The <code>boost</code> words with highest weight will be further + * increased in size. Eye-Candy only. + */ + private int boost; + + /** + * Offset of the region which surrounds the placed words, required to + * translate between mouse position and underlying words. + */ + private Point regionOffset; + + private int antialias = SWT.ON; + + private float boostFactor; + + private Listener hBarListener; + + private Listener resizeListener; + + private Listener paintListener; + + private Listener mouseTrackListener; + + private Listener mouseMoveListener; + + private Listener mouseUpListener; + + private Listener mouseDCListener; + + private Listener mouseDownListener; + + private Listener mouseWheelListener; + + private Listener vBarListener; + + private Set<EventListener> mouseWheelListeners = new HashSet<EventListener>(); + + private Set<EventListener> mouseTrackListeners = new HashSet<EventListener>(); + + private Set<EventListener> mouseMoveListeners = new HashSet<EventListener>(); + + private Set<EventListener> mouseListeners = new HashSet<EventListener>(); + + private Set<SelectionListener> selectionListeners = new HashSet<SelectionListener>(); + + /** + * Creates a new Tag cloud on the given parent. To add scroll bars + * to the cloud, use {@link SWT#HORIZONTAL} and {@link SWT#VERTICAL}. + * @param parent + * @param style + */ + public TagCloud(Composite parent, int style) { + super(parent, style); + highlightColor = new Color(getDisplay(), Display.getDefault().getSystemColor(SWT.COLOR_RED).getRGB()); + gc = new GC(this); + layouter = new DefaultLayouter(5, 5); + setBackground(new Color(getDisplay(), Display.getDefault().getSystemColor(SWT.COLOR_BLACK).getRGB())); + initListeners(); + textLayerImage = new Image(getDisplay(), 100,100); + zoomFit(); + addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + internalDispose(); + } + }); + } + + /** + * Disposes all system resources created in this class. Resources which were + * provided through a {@link ICloudLabelProvider} etc are not disposed. + */ + private void internalDispose() { + removeListeners(); + textLayerImage.dispose(); + if(selectionLayerImage != null) { + selectionLayerImage.dispose(); + } + if(zoomLayerImage != null) { + zoomLayerImage.dispose(); + } + if(!this.isDisposed()) { + gc.dispose(); + } + super.dispose(); + } + + private void removeListeners() { + if(isDisposed()) return; + removeListener(SWT.Paint, paintListener); + if(hBarListener != null) { + removeListener(SWT.H_SCROLL, hBarListener); + } + if(vBarListener != null) { + removeListener(SWT.V_SCROLL, vBarListener); + } + removeListener(SWT.MouseDoubleClick, mouseDCListener); + removeListener(SWT.MouseDown, mouseDownListener); + removeListener(SWT.MouseMove, mouseTrackListener); + removeListener(SWT.MouseUp, mouseUpListener); + removeListener(SWT.Resize, resizeListener); + removeListener(SWT.MouseMove, mouseMoveListener); + removeListener(SWT.MouseWheel, mouseWheelListener); + } + + + /** + * Resets the zoom to 100 % (original size) + */ + public void zoomReset() { + checkWidget(); + if(selectionLayerImage == null) return; + zoomLayerImage = new Image(getDisplay(), selectionLayerImage.getBounds().width, selectionLayerImage.getBounds().height); + GC gc = new GC(zoomLayerImage); + gc.drawImage(selectionLayerImage, 0, 0); + gc.dispose(); + currentZoom = 1; + updateScrollbars(); + redraw(); + } + + public double getZoom() { + checkWidget(); + return currentZoom; + } + + /** + * Resets the zoom such that the generated cloud will + * fit extactly into the available space (unless the zoom + * factor is too small or too large). + */ + public void zoomFit() { + checkWidget(); + if(selectionLayerImage == null) return; + Rectangle imageBound = selectionLayerImage.getBounds(); + Rectangle destRect = getClientArea(); + double sx = (double) destRect.width / (double) imageBound.width; + double sy = (double) destRect.height / (double) imageBound.height; + currentZoom = Math.min(sx, sy); + zoom(currentZoom); + } + + private void zoom(double s) { + checkWidget(); + if(selectionLayerImage == null) return; + if(s < 0.1) s = 0.1; + if(s > 3) s = 3; + int width = (int) (selectionLayerImage.getBounds().width*s); + int height = (int) (selectionLayerImage.getBounds().height*s); + if(width == 0 || height == 0) return; + zoomLayerImage = new Image(getDisplay(), width, height); + Transform tf = new Transform(getDisplay()); + tf.scale((float)s, (float)s); + GC gc = new GC(zoomLayerImage); + gc.setTransform(tf); + gc.drawImage(selectionLayerImage, 0, 0); + gc.dispose(); + tf.dispose(); + currentZoom = s; + updateScrollbars(); + redraw(); + } + + /** + * Zooms in, by the factor of 10 percent. + */ + public void zoomIn() { + checkWidget(); + zoom(currentZoom * 1.1); + redraw(); + } + + /** + * Zooms out, by the factor of 10 percent. + */ + public void zoomOut() { + checkWidget(); + zoom(currentZoom * 0.9); + redraw(); + } + + + /** + * Returns the maximum cloud area. + * @return + */ + protected Rectangle getCloudArea() { + return cloudArea ; + } + + /** + * Returns the font size of the given word. + * By default, this is calculated as <code>8 + (word.weight * maxFontSize)</code>. + * @param word + * @return + */ + private float getFontSize(Word word) { + float size = (float) (word.weight * maxFontSize); + size += minFontSize; + return size; + } + + /** + * Draws a word with the given color. + * @param gc + * @param word + * @param color + */ + private void drawWord(final GC gc, final Word word, final Color color) { + gc.setForeground(color); + Font font = new Font(gc.getDevice(), word.getFontData()); + gc.setFont(font); + gc.setAntialias(antialias); + gc.setAlpha(opacity); + Point stringExtent = word.stringExtent; + gc.setForeground(color); + int xOffset = word.x - regionOffset.x; + int yOffset = word.y - regionOffset.y; + double radian = Math.toRadians(word.angle); + final double sin = Math.abs(Math.sin(radian)); + final double cos = Math.abs(Math.cos(radian)); + + int y = (int) ((cos*stringExtent.y) + (sin*stringExtent.x)); + Transform t = new Transform(gc.getDevice()); + if(word.angle < 0) { + t.translate(xOffset, yOffset + y - (int) (cos*stringExtent.y)); + } else { + t.translate(xOffset + (int) (sin*stringExtent.y), yOffset); + } + t.rotate(word.angle); + gc.setTransform(t); + gc.drawString(word.string, 0, 0, true); + gc.setTransform(null); + t.dispose(); + font.dispose(); + } + + + /** + * Calculates the bounds of each word, by determining + * the {@link Rectangle} a {@link Path} would require + * to render an element. + * @param monitor + */ + protected void calcExtents(IProgressMonitor monitor) { + checkWidget(); + if(monitor != null) { + monitor.subTask("Calculating word boundaries..."); + } + if(wordsToUse == null) return; + double step = 80D/wordsToUse.size(); + double current = 0; + int next = 10; + executors = Executors.newFixedThreadPool(getNumberOfThreads()); + for (final Word word : wordsToUse) { + FontData[] fontData = word.getFontData(); + int fontSize = (int) getFontSize(word); + for (FontData data : fontData) { + data.setHeight((int)fontSize); + } + final Font font = new Font(gc.getDevice(), fontData); + gc.setFont(font); + final Color color = gc.getDevice().getSystemColor(SWT.COLOR_BLACK); + final Point stringExtent = gc.stringExtent(word.string); + FontMetrics fm = gc.getFontMetrics(); + stringExtent.y = fm.getHeight(); + executors.execute(new Runnable() { + @Override + public void run() { + double radian = Math.toRadians(word.angle); + final double sin = Math.abs(Math.sin(radian)); + final double cos = Math.abs(Math.cos(radian)); + final int x = (int) ((cos*stringExtent.x) + (sin*stringExtent.y)); + final int y = (int) ((cos*stringExtent.y) + (sin*stringExtent.x)); + ImageData id = createImageData(word, font, stringExtent, sin, + cos, x, y, color); + calcWordExtents(word, id); + font.dispose(); + } + }); + if(monitor != null) { + current += step; + if(current > next) { + monitor.worked(5); + next += 5; + } + } + } + executors.shutdown(); + try { + executors.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Collections.sort(wordsToUse, new Comparator<Word>() { + + @Override + public int compare(Word o1, Word o2) { + return (o2.width * o2.height) - (o1.width * o1.height); + } + }); + short i = 1; + for (Word word : wordsToUse) { + word.id = i++; + } + } + + private ImageData createImageData(final Word word, Font font, + Point stringExtent, final double sin, final double cos, int x, int y, Color color) { + Image img = new Image(null, x, y); + word.width = x; + word.height = y; + word.stringExtent = stringExtent; + GC g = new GC(img); + g.setAntialias(antialias); + g.setForeground(color); + Transform t = new Transform(img.getDevice()); + if(word.angle < 0) { + t.translate(0,img.getBounds().height - (int) (cos*stringExtent.y)); + } else { + t.translate((int) (sin*stringExtent.y), 0); + } + t.rotate(word.angle); + g.setTransform(t); + g.setFont(font); + // Why is drawString sooo slow? between 30 and 90 percent of the whole + // draw time... + g.drawString(word.string, 0, 0, false); + int max = Math.max(x,y); + int tmp = TREE_SIZE; + while(max < tmp) { + tmp = tmp/2; + } + tmp = tmp*2; + SmallRect root = new SmallRect(0, 0, tmp, tmp); + word.tree = new RectTree(root, RESOLUTION); + final ImageData id = img.getImageData(); + g.dispose(); + img.dispose(); + return id; + } + + + /** + * Calculates the extents of a word, based on its rendered image. + */ + private void calcWordExtents(final Word word, final ImageData id) { + final int[] pixels = new int[id.width]; + final boolean[][] matrix = new boolean[id.height][id.width]; + for (int y = 0; y < id.height; y++) { + id.getPixels(0, y, id.width, pixels, 0); + for (int i = 0; i < pixels.length; i++) { + if (pixels[i] == 0) { + matrix[y][i] = true; + } + } + } + for(int i = 0; i < id.width; i+= RESOLUTION) { + for(int j = 0; j < id.height; j += RESOLUTION) { + final int x = Math.max(0, i-1); + final int y = Math.max(0, j-1); + final int xMax = Math.min(i+RESOLUTION+2, id.width); + final int yMax = Math.min(j+RESOLUTION+2, id.height); +found: for(int a = x; a < xMax; a++) { + for(int b = y; b < yMax; b++) { + if(matrix[b][a]) { + SmallRect r = new SmallRect(i, j, RESOLUTION, RESOLUTION); + word.tree.insert(r, word.id); + break found; + } + } + } + } + } + word.tree.releaseRects(); + } + + /** + * Generates the layout of the given words. + * @param wordsToUse + * @param monitor may be <code>null</code>. + * @return the number of words which could be placed + */ + protected int layoutWords(Collection<Word> wordsToUse, IProgressMonitor monitor) { + checkWidget(); + if(monitor != null) { + monitor.subTask("Placing words..."); + } + region = new Region(); + final Rectangle cloudArea = getCloudArea(); + int w = cloudArea.width; + int h = cloudArea.height; + double current = 0; + int next = 10; + final Image tmpImage = new Image(getDisplay(), w, h); + GC gc = new GC(tmpImage); + gc.setBackground(getBackground()); + gc.setTextAntialias(SWT.ON); + gc.setBackground(getBackground()); + gc.fillRectangle(tmpImage.getBounds()); + executors = Executors.newFixedThreadPool(1); + int success = 0; + if(wordsToUse != null) { + double step = 100D / wordsToUse.size(); + long lTime = 0; + final GC g = gc; + for (Word word : wordsToUse) { + long s = System.currentTimeMillis(); + Point point = layouter.getInitialOffset(word, cloudArea); + boolean result = layouter.layout(point, word, cloudArea, cloudMatrix); + lTime += System.currentTimeMillis() - s; + if(!result) { + System.err.println("Failed to place " + word.string); + continue; + } + success++; + region.add(word.x, word.y, word.width, word.height); + final Word wrd = word; + executors.execute(new Runnable() { + + @Override + public void run() { + drawWord(g, wrd, wrd.getColor()); + } + }); + current += step; + if(current > next) { + next += 5; + if(monitor != null) { + monitor.worked(5); + } +// executors.submit(new Runnable() { +// +// @Override +// public void run() { +// Rectangle r = region.getBounds(); +// if(textLayerImage != null) { +// textLayerImage.dispose(); +// } +// textLayerImage = new Image(getDisplay(), r.width, r.height); +// GC g2 = new GC(textLayerImage); +// g2.drawImage(tmpImage, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height); +// g2.dispose(); +// if(selectionLayerImage != null) { +// selectionLayerImage.dispose(); +// } +// selectionLayerImage = new Image(getDisplay(), r.width, r.height); +// g2 = new GC(selectionLayerImage); +// g2.drawImage(textLayerImage, 0, 0); +// g2.dispose(); +// zoomReset(); +// } +// }); + + } + + } + executors.shutdown(); + try { + executors.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + Rectangle r = region.getBounds(); + gc.dispose(); + if(textLayerImage != null) { + textLayerImage.dispose(); + } + r.width += 5; + r.height += 5; + textLayerImage = new Image(getDisplay(), r.width, r.height); + gc = new GC(textLayerImage); + if(r.width > tmpImage.getBounds().width - r.x || r.height >= tmpImage.getBounds().width - r.y) { + MessageDialog.openError(getShell(), "Failed to place image", "The drawn image does not fit into the available region."); + tmpImage.dispose(); + region.dispose(); + gc.dispose(); + return 0; + } + gc.drawImage(tmpImage, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height); + this.regionOffset = new Point(r.x, r.y); + tmpImage.dispose(); + gc.dispose(); + selectionLayerImage = new Image(getDisplay(), r.width, r.height); + gc = new GC(selectionLayerImage); + gc.drawImage(textLayerImage, 0, 0); + gc.dispose(); + region.dispose(); + zoomReset(); + if(monitor != null) { + monitor.worked(10); + } + return success; + } + + /** + * Sets the given list as input of the tag cloud, + * replacing any previous content. By default, + * available word positions will be determined in-order, + * starting with the element at position 0. + * + * @param values + * @param maxWords + */ + public int setWords(List<Word> values, IProgressMonitor monitor) { + checkWidget(); + Assert.isLegal(values != null, "List must not be null!"); + for (Word word : values) { + Assert.isLegal(word != null, "Word must not be null!"); + Assert.isLegal(word.string != null, "Word must define a string!"); + Assert.isLegal(word.getColor() != null, "A word must define a color"); + Assert.isLegal(word.getFontData() != null, "A word must define a fontdata array"); + Assert.isLegal(word.weight >= 0, "Word weight must be between 0 and 1 (inclusive), but value was " + word.weight); + Assert.isLegal(word.weight <= 1, "Word weight must be between 0 and 1 (inclusive), but value was " + word.weight); + Assert.isLegal(word.angle >= -90, "Angle must be between -90 and +90 (inclusive), but was " + word.angle); + Assert.isLegal(word.angle <= 90, "Angle must be between -90 and +90 (inclusive), but was " + word.angle); + } + this.wordsToUse = new ArrayList<Word>(values); + if(boost > 0) { + double factor = boostFactor; + int i = boost; + for (Word word : values) { + if(factor <= 1) { + break; + } + word.weight *= factor; + factor-= 0.2; + i--; + if(i == 0) break; + } + } + return layoutCloud(monitor, true); + } + + /** + * Reset the initial matrix + */ + private void resetLayout() { + if(cloudMatrix == null) cloudMatrix = new short[TREE_SIZE][TREE_SIZE]; + for(int i = 0; i < cloudMatrix.length; i++) { + for(int j = 0; j < cloudMatrix[i].length; j++) { + cloudMatrix[i][j] = -1; + } + } + } + + private int getNumberOfThreads() { + return Runtime.getRuntime().availableProcessors(); + } + + /** + * Initialize internal listeners (scrollbar, mouse, paint...). + */ + private void initListeners() { + if(initialized) return; + initialized = true; + final ScrollBar hBar = this.getHorizontalBar(); + if(hBar != null) { + hBarListener = new Listener() { + @Override + public void handleEvent (Event e) { + int hSelection = hBar.getSelection(); + int destX = -hSelection - origin.x; + Rectangle rect = zoomLayerImage.getBounds(); + TagCloud.this.scroll (destX, 0, 0, 0, rect.width, rect.height, false); + origin.x = -hSelection; + } + }; + hBar.addListener (SWT.Selection, hBarListener); + } + final ScrollBar vBar = this.getVerticalBar(); + if(vBar != null) { + vBarListener = new Listener() { + @Override + public void handleEvent (Event e) { + int vSelection = vBar.getSelection (); + int destY = -vSelection - origin.y; + Rectangle rect = zoomLayerImage.getBounds(); + TagCloud.this.scroll (0, destY, 0, 0, rect.width, rect.height, false); + origin.y = -vSelection; + } + }; + vBar.addListener (SWT.Selection, vBarListener); + } + resizeListener = new Listener() { + @Override + public void handleEvent (Event e) { + updateScrollbars(); + TagCloud.this.redraw(); + } + }; + this.addListener (SWT.Resize, resizeListener); + paintListener = new Listener() { + @Override + public void handleEvent (Event e) { + GC gc = e.gc; + if(zoomLayerImage == null) return; + Rectangle rect = zoomLayerImage.getBounds(); + Rectangle client = TagCloud.this.getClientArea(); + int marginWidth = client.width - rect.width; + gc.setBackground(getBackground()); + if (marginWidth > 0) { + gc.fillRectangle(rect.width, 0, marginWidth, client.height); + } + int marginHeight = client.height - rect.height; + if (marginHeight > 0) { + gc.fillRectangle(0, rect.height, client.width, marginHeight); + } + gc.drawImage(zoomLayerImage, origin.x, origin.y); + } + }; + this.addListener (SWT.Paint, paintListener); + mouseTrackListener = new Listener() { + @Override + public void handleEvent(Event event) { + Word word = getWordAt(new Point(event.x, event.y)); + MouseEvent me = createMouseEvent(event, word); + if(currentWord != null) { + if(word == currentWord) { + fireMouseEvent(me, SWT.MouseHover, mouseTrackListeners); + } else { + currentWord = null; + fireMouseEvent(me, SWT.MouseExit, mouseTrackListeners); + } + } + if(currentWord == null && word != null) { + currentWord = word; + fireMouseEvent(me, SWT.MouseEnter, mouseTrackListeners); + } + } + }; + this.addListener(SWT.MouseMove, mouseTrackListener); + mouseMoveListener = new Listener() { + @Override + public void handleEvent(Event event) { + Word word = getWordAt(new Point(event.x, event.y)); + MouseEvent me = createMouseEvent(event, word); + fireMouseEvent(me, SWT.MouseMove, mouseMoveListeners); + } + }; + this.addListener(SWT.MouseMove, mouseMoveListener); + mouseUpListener = new Listener() { + @Override + public void handleEvent(Event event) { + Word word = getWordAt(new Point(event.x, event.y)); + MouseEvent me = createMouseEvent(event, word); + fireMouseEvent(me, SWT.MouseUp, mouseListeners); + } + }; + this.addListener(SWT.MouseUp, mouseUpListener); + mouseDCListener = new Listener() { + @Override + public void handleEvent(Event event) { + Word word = getWordAt(new Point(event.x, event.y)); + MouseEvent me = createMouseEvent(event, word); + fireMouseEvent(me, SWT.MouseDoubleClick, mouseListeners); + } + }; + this.addListener(SWT.MouseDoubleClick, mouseDCListener); + mouseDownListener = new Listener() { + @Override + public void handleEvent(Event event) { + Word word = getWordAt(new Point(event.x, event.y)); + MouseEvent me = createMouseEvent(event, word); + fireMouseEvent(me, SWT.MouseDown, mouseListeners); + } + }; + this.addListener(SWT.MouseDown, mouseDownListener); + mouseWheelListener = new Listener() { + @Override + public void handleEvent(Event event) { + Word word = getWordAt(new Point(event.x, event.y)); + MouseEvent me = createMouseEvent(event, word); + fireMouseEvent(me, SWT.MouseWheel, mouseWheelListeners); + } + }; + this.addListener(SWT.MouseWheel, mouseWheelListener); + } + + /** + * Translates the given point in screen coordinates to the corresponding + * point in the (zoomed and scrolled) image and returns the {@link Word} + * at this position, or <code>null</code>, if no word exists at this + * position. + * @param point + * @return + */ + private Word getWordAt(Point point) { + if(cloudMatrix == null || regionOffset == null) return null; + Point translatedMousePos = translateMousePos(point.x, point.y); + translatedMousePos.x += regionOffset.x; + translatedMousePos.y += regionOffset.y; + int x = translatedMousePos.x/RESOLUTION; + int y = translatedMousePos.y/RESOLUTION; + if(x >= cloudMatrix.length || y >= cloudMatrix[x].length) { + return null; + } + short wordId = cloudMatrix[x][y]; + if(wordId > 0) { + Word clicked = wordsToUse.get(wordId-1); + return clicked; + } + return null; + } + + /** + * Translates the current mouse position, such that it + * corresponds to scroll bars and zoom. + * @param x + * @param y + * @return + */ + private Point translateMousePos(final int x, final int y) { + final Point point = new Point(x-origin.x, y-origin.y); + point.x /= currentZoom; + point.y /= currentZoom; + return point; + } + + @Override + public void addMouseListener(MouseListener listener) { + checkWidget(); + Assert.isLegal(listener != null); + mouseListeners.add(listener); + } + + @Override + public void addMouseMoveListener(MouseMoveListener listener) { + checkWidget(); + Assert.isLegal(listener != null); + mouseMoveListeners.add(listener); + } + + @Override + public void addMouseTrackListener(MouseTrackListener listener) { + checkWidget(); + Assert.isLegal(listener != null); + mouseTrackListeners.add(listener); + } + + @Override + public void addMouseWheelListener(MouseWheelListener listener) { + checkWidget(); + Assert.isLegal(listener != null); + mouseWheelListeners.add(listener); + } + + public void addSelectionListener(SelectionListener listener) { + checkWidget(); + Assert.isLegal(listener != null); + selectionListeners .add(listener); + } + + @Override + public void removeMouseListener(MouseListener listener) { + checkWidget(); + mouseListeners.remove(listener); + } + + @Override + public void removeMouseMoveListener(MouseMoveListener listener) { + checkWidget(); + mouseMoveListeners.remove(listener); + } + + @Override + public void removeMouseTrackListener(MouseTrackListener listener) { + checkWidget(); + mouseTrackListeners.remove(listener); + } + + @Override + public void removeMouseWheelListener(MouseWheelListener listener) { + checkWidget(); + mouseWheelListeners.remove(listener); + } + + public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + selectionListeners.remove(listener); + } + + private MouseEvent createMouseEvent(Event event, Word word) { + MouseEvent me = new MouseEvent(event); + me.x = event.x - origin.x; + me.y = event.y - origin.y; + me.data = word; + me.widget = TagCloud.this; + me.display = Display.getCurrent(); + return me; + } + + private void fireMouseEvent(MouseEvent me, int type, Set<EventListener> listeners) { + for (EventListener listener : listeners) { + if(listener instanceof MouseListener) { + MouseListener ml = (MouseListener) listener; + switch(type) { + case SWT.MouseUp: ml.mouseUp(me); break; + case SWT.MouseDoubleClick: ml.mouseDoubleClick(me); break; + case SWT.MouseDown: ml.mouseDown(me); break; + } + } + if(listener instanceof MouseTrackListener) { + MouseTrackListener ml = (MouseTrackListener) listener; + switch(type) { + case SWT.MouseEnter: ml.mouseEnter(me); break; + case SWT.MouseExit: ml.mouseExit(me); break; + case SWT.MouseHover: ml.mouseHover(me); break; + } + } + if(listener instanceof MouseMoveListener) { + MouseMoveListener ml = (MouseMoveListener) listener; + switch(type) { + case SWT.MouseMove: ml.mouseMove(me); break; + } + } + if(listener instanceof MouseWheelListener) { + MouseWheelListener ml = (MouseWheelListener) listener; + switch(type) { + case SWT.MouseWheel: ml.mouseScrolled(me); break; + } + } + } + } + + /** + * Marks the set of elements as selected. + * @param words must not be <code>null</code>. + */ + public void setSelection(Set<Word> words) { + checkWidget(); + Assert.isNotNull(words, "Selection must not be null!"); + if(wordsToUse == null) return; + Set<Word> selection = new HashSet<Word>(words); + selection.retainAll(wordsToUse); + int w = textLayerImage.getBounds().width; + int h = textLayerImage.getBounds().height; + if(selectionLayerImage != null) { + selectionLayerImage.dispose(); + } + selectionLayerImage = new Image(getDisplay(), w, h); + GC gc = new GC(selectionLayerImage); + gc.drawImage(textLayerImage, 0, 0); + for (Word word : selection) { + drawWord(gc, word, highlightColor); + } + if(!selection.equals(this.selection)) { + this.selection = selection; + fireSelectionChanged(); + } + gc.dispose(); + zoom(currentZoom); + redraw(); + } + + private void fireSelectionChanged() { + Event e = new Event(); + e.widget = this; + final SelectionEvent event = new SelectionEvent(e); + event.data = getSelection(); + event.widget = this; + event.display = Display.getCurrent(); + for (SelectionListener listener : selectionListeners) { + listener.widgetSelected(event); + } + } + + public void redrawTextLayerImage() { + if(wordsToUse == null) return; + GC gc = new GC(textLayerImage); + gc.setBackground(getBackground()); + gc.fillRectangle(0, 0, textLayerImage.getBounds().width, textLayerImage.getBounds().height); + for (Word word : wordsToUse) { + drawWord(gc, word, word.getColor()); + } + gc.dispose(); + setSelection(getSelection()); + } + + /** + * Returns the set of selected elements. + * Never returns <code>null</code>. + * @return + */ + public Set<Word> getSelection() { + checkWidget(); + Set<Word> copy = new HashSet<Word>(selection); + return copy; + } + + /** + * Sets the highlight color of the cloud. Default color + * is red. + * @param color + */ + public void setSelectionColor(Color color) { + checkWidget(); + Assert.isLegal(color != null, "Color must not be null!"); + this.highlightColor = color; + } + + @Override + public void setBackground(Color color) { + checkWidget(); + Assert.isLegal(color != null, "Color must not be null!"); + super.setBackground(color); + } + + /** + * Does a full relayout of all displayed elements. + * @param monitor + * @return + */ + public int layoutCloud(IProgressMonitor monitor, boolean recalc) { + checkWidget(); + resetLayout(); + if(selectionLayerImage != null) { + selectionLayerImage.dispose(); + selectionLayerImage = null; + } + regionOffset = new Point(0, 0); + if(textLayerImage != null) textLayerImage.dispose(); + int placedWords = 0; + try { + if(recalc) { + calcExtents(monitor); + } + placedWords = layoutWords(wordsToUse, monitor); + } catch (Exception e) { + MessageDialog.openError(getShell(), "Exception while layouting data", "An exception occurred while layouting: " + e.getMessage()); + e.printStackTrace(); + } + zoomFit(); + redraw(); + updateScrollbars(); + return placedWords; + } + + private void updateScrollbars() { + if(zoomLayerImage == null) { + return; + } + Rectangle rect = zoomLayerImage.getBounds(); + Rectangle client = getClientArea(); + ScrollBar hBar = getHorizontalBar(); + ScrollBar vBar = getVerticalBar(); + if(hBar != null) { + hBar.setMaximum (rect.width); + hBar.setThumb (Math.min (rect.width, client.width)); + int hPage = rect.width - client.width; + int hSelection = hBar.getSelection (); + if (hSelection >= hPage) { + if (hPage <= 0) hSelection = 0; + origin.x = -hSelection; + } + } + if(vBar != null) { + vBar.setMaximum (rect.height); + vBar.setThumb (Math.min (rect.height, client.height)); + int vPage = rect.height - client.height; + int vSelection = vBar.getSelection (); + if (vSelection >= vPage) { + if (vPage <= 0) vSelection = 0; + origin.y = -vSelection; + } + } + } + + /** + * Sets the maximum font size (which must be a value greater 0). Note that strings + * which are too large to fit into the cloud region will be skipped. By default, this + * value is 500. + * @param maxSize + */ + public void setMaxFontSize(int maxSize) { + checkWidget(); + Assert.isLegal(maxSize > 0, "Font Size must be greater than zero, but was " + maxSize + "!"); + maxFontSize = maxSize; + } + + /** + * Sets the opacity of the words, which must be a value between 0 and 255 (inclusive). + * Currently not very useful... + * @param opacity + */ + public void setOpacity(int opacity) { + checkWidget(); + Assert.isLegal(opacity > 0, "Opacity must be greater than zero: " + opacity); + Assert.isLegal(opacity < 256, "Opacity must be less than 256: " + opacity); + this.opacity = opacity; + } + + /** + * Sets the minimum font size. Should be a reasonable value > 0 (twice of {@link TagCloud#RESOLUTION} + * is recommended). By default, this value is 12. + * @param size + */ + public void setMinFontSize(int size) { + checkWidget(); + Assert.isLegal(size > 0, "Font Size must be greater zero: " + size); + this.minFontSize = size; + } + + /** + * Returns the {@link ImageData} of the text layer image (all rendered elements, unscaled, + * without highlighted selection). Can be used to print or export the cloud. + * @return + */ + public ImageData getImageData() { + checkWidget(); + if(textLayerImage == null) return null; + return textLayerImage.getImageData(); + } + + /** + * Enable boosting for the first <code>boost</code> + * elements. By default, no elements are boosted. + * @param boost + */ + public void setBoost(int boost) { + checkWidget(); + Assert.isLegal(boost >= 0, "Boost cannot be negative"); + this.boost = boost; + } + + /** + * Enable or disable antialiasing. Enabled by default. + * @param enabled + */ + public void setAntiAlias(boolean enabled) { + checkWidget(); + if(enabled) { + antialias = SWT.ON; + } else { + antialias = SWT.OFF; + } + } + +// /** +// * Work in progress - still broken positioning +// * @param w +// * @throws IOException +// */ +// public void toSVG(Writer w) throws IOException { +// int counter = 1; +// w.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" + +// "<!-- Created with Eclipse Tag Cloud -->\n" + +// "<svg\n" + +// "xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" + +// "xmlns:cc=\"http://creativecommons.org/ns#\"\n" + +// "xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n" + +// "xmlns:svg=\"http://www.w3.org/2000/svg\"\n" + +// "xmlns=\"http://www.w3.org/2000/svg\"\n" + +// "version=\"1.1\"\n" + +// "width=\"" + textLayerImage.getBounds().width + "\"\n" + +// "height=\"" + textLayerImage.getBounds().height + "\"\n" + +// "id=\"svg2\">\n" + +// "<defs\n" + +// "id=\"defs4\" />\n" + +// "<metadata\n" + +// "id=\"metadata7\">\n" + +// "<rdf:RDF>\n" + +// "<cc:Work\n" + +// "rdf:about=\"\">\n" + +// "<dc:format>image/svg+xml</dc:format>\n" + +// "<dc:type\n" + +// "rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />\n" + +// "<dc:title></dc:title>\n" + +// "</cc:Work>\n" + +// "</rdf:RDF>\n" + +// "</metadata>\n" + +// "<g\n" + +// "id=\"layer1\">\n"); +// GC tmp = new GC(Display.getDefault()); +// String bg = Integer.toHexString(getBackground().getRed()) + Integer.toHexString(getBackground().getGreen()) + Integer.toHexString(getBackground().getBlue()); +// w.append("<rect x=\"" + 0 + "\" y=\"" + 0 + "\" width=\"" + textLayerImage.getBounds().width + "\" height=\"" + textLayerImage.getBounds().height + "\" style=\"fill:" + bg + ";stroke:#006600;\"/>"); +// for (Word word : wordsToUse) { +// String id = "text" + counter++; +// FontData fd = word.fontData[0]; +// String style = "font-size:" + fd.getHeight()+"px;" + +// "font-family:" + fd.getName() + ";"; +// String text = word.string; +// int x = 0; +// int y = 0; +// double radian = Math.toRadians(word.angle); +// final double sin = Math.abs(Math.sin(radian)); +// final double cos = Math.abs(Math.cos(radian)); +// float fontSize = getFontSize(word); +// Font font = new Font(tmp.getDevice(), word.fontData); +// Path p = new Path(tmp.getDevice()); +// p.addString(word.string, 0, 0, font); +// float[] bounds = new float[4]; +// p.getBounds(bounds); +// p.dispose(); +// gc.setFont(font); +// //Point stringExtent = gc.stringExtent(word.string); +// font.dispose(); +// if(word.angle < 0) { +// y = word.height - (int) ( cos * fontSize); +// } else { +// x = (int) (sin * fontSize); +// } +// x += word.x - regionOffset.x; +// y += word.y - regionOffset.y; +// +//// w.append("<rect x=\"" + 0 + "\" y=\"" + 0 + "\" width=\"" + stringExtent.x + "\" height=\"" + stringExtent.y + "\" style=\"fill:none;stroke:#006600;\"" + +//// " transform=\"translate(" + x + "," + y + ") rotate(" + word.angle + ")\"/>"); +// +// int xOff = (int) (-bounds[0] + bounds[2]/2); +// int yOff = (int)(bounds[3] - bounds[1]); +// String color = Integer.toHexString(word.color.getRed()) + Integer.toHexString(word.color.getGreen()) + Integer.toHexString(word.color.getBlue()); +// String fullString = "\n<text " +// + "x=\"" + xOff + "\"\n" +// + "y=\"" + yOff + "\"\n" +// + "text-anchor=\"middle\"\n" +// + "transform = \"translate(" + x + "," + y + ") rotate(" + word.angle+")\"\n" +// + "id=\"" + id + "\"\n" +// + "xml:space=\"preserve\"\n" +// + "style=\"font-size:40px;fill:#" + color + ";fill-opacity:1;stroke:none;font-family:Sans\">\n" +// + "<tspan " +// + "style=\""+style+"\">" +// + text + "</tspan>\n" +// +"</text>\n"; +// +// w.append(fullString); +// } +// tmp.dispose(); +// w.append("</g>\n</svg>\n"); +// } + + public void setBoostFactor(float boostFactor) { + Assert.isLegal(boostFactor != 0); + this.boostFactor = boostFactor; + } + + public Color getSelectionColor() { + return highlightColor; + } + + public void setLayouter(ILayouter layouter) { + checkWidget(); + Assert.isLegal(layouter != null, "Layouter must not be null!"); + this.layouter = layouter; + } + + public int getMaxFontSize() { + checkWidget(); + return maxFontSize; + } + + public int getMinFontSize() { + checkWidget(); + return minFontSize; + } + + public int getBoost() { + checkWidget(); + return boost; + } + + public float getBoostFactor() { + checkWidget(); + return boostFactor; + } + + public List<Word> getWords() { + return wordsToUse; + } + + public ILayouter getLayouter() { + return layouter; + } + + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/TagCloudViewer.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/TagCloudViewer.java new file mode 100644 index 0000000..009dbbb --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/TagCloudViewer.java @@ -0,0 +1,375 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.viewers.ContentViewer; +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.MouseWheelListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Control; +import org.eclipse.zest.cloudio.layout.ILayouter; + + +/** + * A model-based adapter for a {@link TagCloud}. + * @author sschwieb + */ +public class TagCloudViewer extends ContentViewer { + + private TagCloud cloud; + + private Set<Word> selection = new HashSet<Word>(); + + private Map<Object, Word> objectMap = new HashMap<Object, Word>(); + + private int maxWords = 300; + + private IProgressMonitor monitor; + + /** + * Create a new TagCloudViewer for the given {@link TagCloud}, + * which must not be <code>null</code>. + * @param cloud + */ + public TagCloudViewer(TagCloud cloud) { + Assert.isLegal(cloud != null, "TagCloud must not be null!"); + Assert.isLegal(!cloud.isDisposed(), "TagCloud must not be disposed!"); + this.cloud = cloud; + initListeners(); + } + /** + * Initialize the default tag cloud listeners. + * Can be overridden to modify the behaviour of the viewer. + */ + protected void initListeners() { + initSelectionListener(); + initMouseWheelListener(); + initToolTipSupport(); + } + + /** + * Initialize tool tip support when the cursor + * hovers a word. + */ + protected void initToolTipSupport() { + cloud.addMouseTrackListener(new MouseTrackListener() { + + @Override + public void mouseHover(MouseEvent e) {} + + @Override + public void mouseExit(MouseEvent e) { + cloud.setToolTipText(null); + } + + @Override + public void mouseEnter(MouseEvent e) { + Word word = (Word) e.data; + ICloudLabelProvider labelProvider = (ICloudLabelProvider) getLabelProvider(); + cloud.setToolTipText(labelProvider.getToolTip(word.data)); + } + }); + } + + /** + * Initialize the mouse wheel listener to support + * zooming in and out. + */ + protected void initMouseWheelListener() { + cloud.addMouseWheelListener(new MouseWheelListener() { + + @Override + public void mouseScrolled(MouseEvent e) { + if(e.count > 0) { + cloud.zoomIn(); + } else { + cloud.zoomOut(); + } + + } + }); + } + + /** + * Initialize default selection behaviour: Words can + * be selected by mouse click, and selection listeners + * are notified when the selection changed. + */ + protected void initSelectionListener() { + cloud.addMouseListener(new MouseListener() { + + @Override + public void mouseUp(MouseEvent e) { + Word word = (Word) e.data; + if(word == null) return; + boolean remove = selection.remove(word); + if(!remove) selection.add(word); + cloud.setSelection(selection); + } + + @Override + public void mouseDown(MouseEvent e) { + + } + + @Override + public void mouseDoubleClick(MouseEvent e) { + } + }); + cloud.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + List<Object> data = new ArrayList<Object>(); + Set<Word> selected = (Set<Word>) e.data; + for (Word word : selected) { + if(word.data != null) { + data.add(word.data); + } + } + StructuredSelection selection = new StructuredSelection(data); + fireSelectionChanged(new SelectionChangedEvent(TagCloudViewer.this, selection)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.viewers.Viewer#getControl() + */ + @Override + public Control getControl() { + return getCloud(); + } + + /** + * Returns the currently selected elements, as an + * {@link IStructuredSelection}. Returns an empty + * selection if no elements are selected. + */ + @Override + public ISelection getSelection() { + List<Object> elements = new ArrayList<Object>(); + for (Word word : selection) { + elements.add(word.data); + } + return new StructuredSelection(elements); + } + + @Override + public void refresh() { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean) + */ + @Override + public void setSelection(ISelection selection, boolean reveal) { + this.selection.clear(); + IStructuredSelection sel = (IStructuredSelection) selection; + Iterator<?> iterator = sel.iterator(); + while(iterator.hasNext()) { + Object next = iterator.next(); + Word word = objectMap.get(next); + if(word != null) { + this.selection.add(word); + } + } + cloud.setSelection(this.selection); + } + + /** + * Resets the {@link TagCloud}. If <code>recalc</code> is + * <code>true</code>, the displayed elements will be updated + * with the values provided by used {@link ICloudLabelProvider}. + * Otherwise, the cloud will only be re-layouted, keeping fonts, + * colors and angles untouched. + * @param monitor + * @param recalc + */ + public void reset(IProgressMonitor monitor, boolean recalc) { + cloud.layoutCloud(monitor, recalc); + } + + /** + * Returns the {@link TagCloud} managed by this viewer. + * @return + */ + public TagCloud getCloud() { + return cloud; + } + + /** + * Sets the label provider of this viewer, which must be an + * {@link ICloudLabelProvider}. + */ + @Override + public void setLabelProvider(IBaseLabelProvider labelProvider) { + super.setLabelProvider(labelProvider); + Assert.isLegal(labelProvider instanceof ICloudLabelProvider); + } + + /** + * Sets the content provider of this viewer, which must be + * an {@link IStructuredContentProvider}. + */ + @Override + public void setContentProvider(IContentProvider contentProvider) { + Assert.isLegal(contentProvider instanceof IStructuredContentProvider); + super.setContentProvider(contentProvider); + + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.viewers.Viewer#inputChanged(java.lang.Object, java.lang.Object) + */ + @Override + protected void inputChanged(Object input, Object oldInput) { + selection.clear(); + objectMap.clear(); + IStructuredContentProvider contentProvider = (IStructuredContentProvider) getContentProvider(); + Object[] elements = contentProvider.getElements(input); + List<Word> words = new ArrayList<Word>(); + ICloudLabelProvider labelProvider = (ICloudLabelProvider) getLabelProvider(); + short i = 0; + for (Object element : elements) { + Word word = new Word(labelProvider.getLabel(element)); + word.setColor(labelProvider.getColor(element)); + word.weight = labelProvider.getWeight(element); + word.setFontData(labelProvider.getFontData(element)); + word.angle = labelProvider.getAngle(element); + word.data = element; + Assert.isLegal(word.string != null, "Labelprovider must return a String for each element"); + Assert.isLegal(word.getColor() != null, "Labelprovider must return a Color for each element"); + Assert.isLegal(word.getFontData() != null, "Labelprovider must return a FontData for each element"); + Assert.isLegal(word.weight >= 0, "Labelprovider must return a weight between 0 and 1 (inclusive), but value was " + word.weight); + Assert.isLegal(word.weight <= 1, "Labelprovider must return a weight between 0 and 1 (inclusive), but value was " + word.weight); + Assert.isLegal(word.angle >= -90, "Angle of an element must be between -90 and +90 (inclusive), but was " + word.angle); + Assert.isLegal(word.angle <= 90, "Angle of an element must be between -90 and +90 (inclusive), but was " + word.angle); + words.add(word); + i++; + word.id = i; + objectMap.put(element, word); + if(i == maxWords) break; + } + selection.clear(); + if(monitor != null) { + monitor.subTask("Layouting..."); + } + cloud.setWords(words, monitor); + } + + /** + * Sets the maximum number of elements which will be + * displayed by the cloud. Note that there is no guarantee + * that this amount of elements will actually be displayed, + * as this depends on additional factors. + * @return + */ + public void setMaxWords(int words) { + this.maxWords = words; + } + + /** + * Calls {@link TagCloud#zoomFit()} to scale the cloud such + * that it fits the current visible area. + */ + public void zoomFit() { + cloud.zoomFit(); + } + + /** + * Zooms in + */ + public void zoomIn() { + cloud.zoomIn(); + } + + /** + * Zooms out + */ + public void zoomOut() { + cloud.zoomOut(); + } + + /** + * Resets the zoom to 100% + */ + public void zoomReset() { + cloud.zoomReset(); + } + + public void setBoost(int boost) { + cloud.setBoost(boost); + } + + /** + * Returns the maximum number of elements which will be + * displayed by the cloud. Note that there is no guarantee + * that this amount of elements will actually be displayed, + * as this depends on additional factors. + * @return + */ + public int getMaxWords() { + return maxWords; + } + + /** + * Same as {@link TagCloudViewer#setInput(Object)}, but with + * an {@link IProgressMonitor} to provide feedback during the + * layout phase. + * @param input + * @param progressMonitor + */ + public void setInput(Object input, IProgressMonitor progressMonitor) { + this.monitor = progressMonitor; + super.setInput(input); + this.monitor = null; + } + + public void setBoostFactor(float boostFactor) { + cloud.setBoostFactor(boostFactor); + } + + public void setLayouter(ILayouter layouter) { + cloud.setLayouter(layouter); + } + + public ILayouter getLayouter() { + return cloud.getLayouter(); + } + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/Word.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/Word.java new file mode 100644 index 0000000..efc837b --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/Word.java @@ -0,0 +1,81 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.zest.cloudio.util.RectTree; + +/** + * Helper class which stores all data + * required to render an element. + * @author sschwieb + * + */ +public class Word { + + public Word(String string) { + this.string = string; + } + + public final String string; + + public double weight; + + public int x; + + public int y; + + private Color color; + + public RectTree tree; + + public float angle; + + private FontData[] fontData; + + public FontData[] getFontData() { + return fontData; + } + + public void setFontData(FontData[] fontData) { + Assert.isLegal(fontData != null, "FontData-Array must not be null!"); + this.fontData = fontData.clone(); + } + + public short id; + + public int height; + + public int width; + + public Object data; + + public Point stringExtent; + + @Override + public String toString() { + return string; + } + + public void setColor(Color color) { + Assert.isLegal(color != null, "Color must not be null!"); + Assert.isLegal(!color.isDisposed(), "Color is disposed!"); + this.color = color; + } + + public Color getColor() { + Assert.isLegal(color != null, "Color must not be null!"); + Assert.isLegal(!color.isDisposed(), "Color is disposed!"); + return color; + } + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/layout/DefaultLayouter.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/layout/DefaultLayouter.java new file mode 100644 index 0000000..17cddf3 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/layout/DefaultLayouter.java @@ -0,0 +1,147 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio.layout; + +import java.util.Random; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.zest.cloudio.Word; +import org.eclipse.zest.cloudio.util.RectTree; + +/** + * + * @author sschwieb + * + */ +public class DefaultLayouter implements ILayouter { + + public static final String X_AXIS_VARIATION = "xaxis"; + + + public static final String Y_AXIS_VARIATION = "yaxis"; + + + private Random random = new Random(); + + + /** + * Percentage of x axis variation. By default, searching for free space + * is started in the center of the available area. By increasing this + * value, the start point is moved on the x axis. + * + */ + private int xAxisVariation; + + /** + * Percentage of x axis variation. By default, searching for free space + * is started in the center of the available area. By increasing this + * value, the start point is moved on the y axis. + * + */ + private int yAxisVariation; + + + public DefaultLayouter(int i, int j) { + this.xAxisVariation = i; + this.yAxisVariation = j; + } + + public Point getInitialOffset(Word word, Rectangle cloudArea) { + int xOff = 0; + if(xAxisVariation > 0) { + int range = (cloudArea.width-word.width)/200*xAxisVariation; + if(range > 0) { + xOff = random.nextInt(range); + if(random.nextBoolean()) { + xOff = -xOff; + } + } + } + int yOff = 0; + if(yAxisVariation > 0) { + int range = cloudArea.height/200*yAxisVariation; + if(range > 0) { + yOff = random.nextInt(range); + if(random.nextBoolean()) yOff = -yOff; + } + } + return new Point(xOff, yOff); + } + + /** + * Tries to position the given word in the given area. First a start point is chosen, + * then the {@link RectTree} of the word and the main area is used to detect whether + * the word can be placed at the given position, or not. If not, the current point + * is moved slightly in a spiral manner, similar to the approach of Wordle. + * @param word + * @param cloudArea + * @return + */ + public boolean layout(Point offset, final Word word, final Rectangle cloudArea, short[][] mainTree) { + Assert.isLegal(word != null, "Word cannot be null!"); + Point next = new Point(-word.width/2, -word.height/2); + next.x += random.nextInt(25); + next.y += random.nextInt(25); + double growFactor = 1.6; + offset.x += cloudArea.width/2; + offset.y += cloudArea.height/2; + for(int i = 0; i < 5000; i++) { + final double radius = Math.sqrt((double) (next.x * next.x + next.y * next.y)) + growFactor; + double atan = Math.atan2(next.y, next.x); + if(growFactor > 1.1) { + growFactor -= 0.0007; + } + if(radius < 80) { + atan += 0.7; + } else { + atan += 20 / radius; + } + if(growFactor < 0.0005) { + growFactor = 0.0005; + } + next.x = (int) (radius * Math.cos(atan)); + next.y = (int) (radius * Math.sin(atan)); + word.x = next.x + offset.x; + word.y = next.y + offset.y; + RectTree rt = word.tree; + if(rt == null) break; + rt.move(word.x, word.y); + if(cloudArea.x <= word.x && cloudArea.y <= word.y && cloudArea.x+cloudArea.width >= word.x + word.width && cloudArea.y + cloudArea.height >= word.y + word.height) { + if(rt.fits(mainTree)) { + rt.place(mainTree, word.id); + return true; + } + } + } + return false; + } + + + public void setOption(String optionName, Object object) { + if(X_AXIS_VARIATION.equals(optionName)) { + Integer value = (Integer) object; + Assert.isLegal(value >= 0, "Parameter must be between 0 and 100 (inclusive): " + value); + Assert.isLegal(value <= 100, "Parameter must be between 0 and 100 (inclusive): " + value); + this.xAxisVariation = value; + return; + } + if(Y_AXIS_VARIATION.equals(optionName)) { + Integer value = (Integer) object; + Assert.isLegal(value >= 0, "Parameter must be between 0 and 100 (inclusive): " + value); + Assert.isLegal(value <= 100, "Parameter must be between 0 and 100 (inclusive): " + value); + this.yAxisVariation = value; + return; + } + System.err.println("Unrecognized option: " + optionName); + } + + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/layout/ILayouter.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/layout/ILayouter.java new file mode 100644 index 0000000..79a147b --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/layout/ILayouter.java @@ -0,0 +1,50 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio.layout; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.zest.cloudio.Word; + +/** + * + * @author sschwieb + * + */ +public interface ILayouter { + + /** + * Places the given word within the defined rectangle, starting + * at the initial position. + * @param offset + * @param word + * @param cloudArea + * @param mainTree + * @return + */ + public boolean layout(Point initial, final Word word, final Rectangle cloudArea, short[][] mainTree); + + /** + * Calculates the initial offset of the given word, within the bounds + * of the specified rectangle. The layout algorithm will try to find + * a matching position around the initial offset. + * @param word + * @param cloudArea + * @return + */ + public Point getInitialOffset(Word word, Rectangle cloudArea); + + /** + * Set Layouter-specific options. See {@link DefaultLayouter} + * as an example. + * @param optionName + * @param object + */ + public void setOption(String optionName, Object object); +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/util/RectTree.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/util/RectTree.java new file mode 100644 index 0000000..fe19e67 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/util/RectTree.java @@ -0,0 +1,225 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio.util; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * A two-dimensional tree structure to store non-overlapping + * rectangles. + * @author sschwieb + * + */ +public class RectTree { + + private final int minResolution; + + private short xOffset, yOffset; + + private final RectNode root; + + private LinkedList<RectNode> leaves; + + private static short EMPTY = -1, MISC = 0; + + public Rectangle minBounds = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE, Short.MIN_VALUE, Short.MIN_VALUE); + + private Stack<RectNode> lastPath = new Stack<RectNode>(); + + class RectNode { + + final SmallRect rect; + + private RectNode[] children; + + private final SmallRect[] childAreas; + + short filled = EMPTY; + + public RectNode(SmallRect rect) { + this.rect = rect; + final int width = rect.width/2; + final int height = rect.height/2; + if(rect.width > minResolution) { + this.childAreas = new SmallRect[4]; + // top left + childAreas[0] = new SmallRect(rect.x, rect.y, width, height); + // top right + childAreas[1] = new SmallRect(rect.x+width, rect.y, width, height); + // bottom left + childAreas[2] = new SmallRect(rect.x, rect.y+height, width, height); + // bottom right + childAreas[3] = new SmallRect(rect.x+width, rect.y+height, width, height); + } else { + this.childAreas = null; + } + } + + private int getChildIndex(SmallRect r) { + int index = 0; + if(r.y>= childAreas[3].y) { + if(r.x >= childAreas[3].x) { + index = 3; + } else { + index = 2; + } + } else { + if(r.x >= childAreas[1].x) { + index = 1; + } + } + return index; + } + + public void insert(SmallRect r, short id) { + if(rect.width == minResolution) { + filled = id; + return; + } + int i = getChildIndex(r); + lastPath.push(this); + if(children == null) { + children = new RectNode[4]; + } + if(children[i] == null) { + children[i] = new RectNode(childAreas[i]); + } + if(children[i].rect.width >= minResolution && children[i].rect.height >= minResolution) { + children[i].insert(r, id); + if(children[i].rect.width == minResolution) { + children[i].filled = id; + SmallRect c = children[i].rect; + if(c.x < minBounds.x) minBounds.x = c.x; + if(c.y < minBounds.y) minBounds.y = c.y; + if(c.x > minBounds.width) minBounds.width = c.x; + if(c.y > minBounds.height) minBounds.height = c.y; + } + } + boolean filled = true; + if(children != null) { + for(int ix = 0; ix < 4; ix++) { + if(children[ix] == null) { + filled = false; + break; + } + if(children[ix].filled == EMPTY) { + filled = false; + break; + } + } + } + if(filled) { + this.filled = MISC; + } + } + + public boolean isAvailable(final SmallRect oRect) { + if(filled >= MISC) return false; + if(children == null) { + return filled == EMPTY; + } + final int i = getChildIndex(oRect); + if(children[i] == null) return true; + return children[i].isAvailable(oRect); + } + + + public short getWordId(Point position) { + if(filled > 0) return filled; + if(children == null) { + return filled; + } + for(int i = 0; i < childAreas.length; i++) { + if(childAreas[i].intersects(position.x-2, position.y-2, 4, 4) && children[i] != null) { + return children[i].getWordId(position); + } + } + return 0; + } + + } + + public RectTree(SmallRect root, int minResolution) { + this.minResolution = minResolution; + this.root = new RectNode(root); + } + + public void insert(SmallRect r, short id) { + while(!lastPath.isEmpty()) { + RectNode node = lastPath.pop(); + if(node.rect.intersects(r)) { + node.insert(r, id); + return; + } + } + root.insert(r, id); + } + + public void move(int x, int y) { + this.xOffset = (short) x; + this.yOffset = (short) y; + } + + public boolean fits(final short[][] mainTree) { + LinkedList<RectNode> leaves = getLeaves(); + Iterator<RectNode> nodes = leaves.iterator(); + while(nodes.hasNext()) { + RectNode node = nodes.next(); + if(mainTree[(node.rect.x+xOffset)/minResolution][(node.rect.y+yOffset)/minResolution] != EMPTY) { + nodes.remove(); + leaves.addFirst(node); + return false; + } + } + return true; + } + + LinkedList<RectNode> getLeaves() { + if(leaves == null) { + leaves = new LinkedList<RectNode>(); + addLeaves(leaves, root); + } + return leaves; + } + + private void addLeaves(List<RectNode> leaves, RectNode current) { + if(current.children == null) { + if(current.filled != EMPTY) { + leaves.add(current); + } + } else { + for(int i = 0; i < 4; i++) { + if(current.children[i] == null) continue; + addLeaves(leaves, current.children[i]); + } + } + } + + public void place(final short[][] mainTree, short id) { + Collection<RectNode> leaves = getLeaves(); + for (RectNode node : leaves) { + mainTree[(node.rect.x+xOffset)/minResolution][(node.rect.y+yOffset)/minResolution] = id; + } + } + + public void releaseRects() { + getLeaves(); + root.children = null; + } + + + +} diff --git a/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/util/SmallRect.java b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/util/SmallRect.java new file mode 100644 index 0000000..d11aa38 --- a/dev/null +++ b/org.eclipse.zest.cloudio/src/main/java/org/eclipse/zest/cloudio/util/SmallRect.java @@ -0,0 +1,47 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.cloudio.util; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Rectangle; + +/** + * A custom variation of a {@link Rectangle}, which stores + * the required values as short instead of int, thus saving + * some space. + * + * @author sschwieb + * + */ +public class SmallRect { + + final short x, y, width, height; + + public SmallRect(int x, int y, int width, int height) { + this.x = (short) x; + this.y = (short) y; + this.width = (short) width; + this.height = (short) height; + } + + public boolean intersects(SmallRect rect) { + if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + return rect == this || intersects (rect.x, rect.y, rect.width, rect.height); + } + + public boolean intersects (final int x, final int y, final int width, final int height) { + return (x < this.x + this.width) && (y < this.y + this.height) && + (x + width > this.x) && (y + height > this.y); + } + + public String toString () { + return "Rectangle {" + x + ", " + y + ", " + width + ", " + height + "}"; + } + +} diff --git a/org.eclipse.zest.examples.cloudio.build/.project b/org.eclipse.zest.examples.cloudio.build/.project new file mode 100644 index 0000000..6fcd23a --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.build/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.zest.examples.cloudio.build</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/org.eclipse.zest.examples.cloudio.build/pom.xml b/org.eclipse.zest.examples.cloudio.build/pom.xml new file mode 100644 index 0000000..dcbe589 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.build/pom.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.eclipse.zest.cloudio</groupId> + <version>2.0.0-SNAPSHOT</version> + <artifactId>parent</artifactId> + <packaging>pom</packaging> + + <modules> + <module>../org.eclipse.zest.cloudio</module> + <module>../org.eclipse.zest.examples.cloudio</module> + <module>../org.eclipse.zest.examples.cloudio.feature</module> + <module>../org.eclipse.zest.examples.cloudio.rcp</module> + + </modules> + + <properties> + <tycho-version>0.12.0</tycho-version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + </properties> + + <repositories> + <repository> + <id>helios</id> + <layout>p2</layout> + <url>http://download.eclipse.org/releases/helios</url> + <snapshots> + <enabled>true</enabled> + </snapshots> + </repository> + </repositories> + + <pluginRepositories> + <pluginRepository> + <id>sonatype-repository</id> + <url>https://repository.sonatype.org/content/repositories/tycho-014/</url> + <snapshots> + <enabled>true</enabled> + </snapshots> + </pluginRepository> + </pluginRepositories> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>2.3.2</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + <encoding>UTF-8</encoding> + </configuration> + </plugin> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-compiler-plugin</artifactId> + <version>${tycho-version}</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + <encoding>UTF-8</encoding> + </configuration> + </plugin> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-maven-plugin</artifactId> + <version>${tycho-version}</version> + <extensions>true</extensions> + </plugin> + + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>target-platform-configuration</artifactId> + <version>${tycho-version}</version> + <configuration> + <resolver>p2</resolver> + <target> + <artifact> + <groupId>org.eclipse</groupId> + <artifactId>org.eclipse.zest.cloudio</artifactId> + <version>2.0.0-SNAPSHOT</version> + <classifier>cloudio</classifier> + </artifact> + </target> + <ignoreTychoRepositories>false</ignoreTychoRepositories> + <environments> + <environment> <os>macosx</os> <ws>cocoa</ws> <arch>x86_64</arch> </environment> + <environment> <os>macosx</os> <ws>cocoa</ws> <arch>x86</arch> </environment> + <environment> <os>linux</os> <ws>gtk</ws> <arch>x86</arch> </environment> + <environment> <os>linux</os> <ws>gtk</ws> <arch>x86_64</arch> </environment> + <environment> <os>win32</os> <ws>win32</ws> <arch>x86</arch> </environment> + <environment> <os>win32</os> <ws>win32</ws> <arch>x86_64</arch> </environment> + </environments> + </configuration> + </plugin> + </plugins> + </build> + <!-- + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.8</version> + <configuration> + + </configuration> + </plugin> + </plugins> + + </reporting>--> + +</project> diff --git a/org.eclipse.zest.examples.cloudio.feature/.project b/org.eclipse.zest.examples.cloudio.feature/.project new file mode 100644 index 0000000..88f0179 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.feature/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.zest.examples.cloudio.feature</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.pde.FeatureBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.FeatureNature</nature> + </natures> +</projectDescription> diff --git a/org.eclipse.zest.examples.cloudio.feature/build.properties b/org.eclipse.zest.examples.cloudio.feature/build.properties new file mode 100644 index 0000000..64f93a9 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.eclipse.zest.examples.cloudio.feature/feature.xml b/org.eclipse.zest.examples.cloudio.feature/feature.xml new file mode 100644 index 0000000..dc98d14 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.feature/feature.xml @@ -0,0 +1,225 @@ +<?xml version="1.0" encoding="UTF-8"?> +<feature + id="org.eclipse.zest.examples.cloudio.feature" + label="Cloudio Application Feature" + version="2.0.0.qualifier"> + + <description> + Do not install this feature - it is required for the standalone +RCP Application only. + </description> + + <license url="http://www.example.com/license"> + Eclipse Public License -v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS +ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE +OF THIS AGREEMENT. +1. DEFINITIONS +"Contribution" means: +a) in the case of the initial Contributor, the initial code and +documentation distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate +from and are distributed by that particular Contributor. A Contribution +'originates' from a Contributor if it was added to the Program +by such Contributor itself or anyone acting on such Contributor's +behalf. Contributions do not include additions to the Program +which: (i) are separate modules of software distributed in conjunction +with the Program under their own license agreement, and (ii) +are not derivative works of the Program. +"Contributor" means any person or entity that distributes the +Program. +"Licensed Patents " mean patent claims licensable by a Contributor +which are necessarily infringed by the use or sale of its Contribution +alone or when combined with the Program. +"Program" means the Contributions distributed in accordance with +this Agreement. +"Recipient" means anyone who receives the Program under this +Agreement, including all Contributors. +2. GRANT OF RIGHTS +a) Subject to the terms of this Agreement, each Contributor hereby +grants Recipient a non-exclusive, worldwide, royalty-free copyright +license to reproduce, prepare derivative works of, publicly display, +publicly perform, distribute and sublicense the Contribution +of such Contributor, if any, and such derivative works, in source +code and object code form. +b) Subject to the terms of this Agreement, each Contributor hereby +grants Recipient a non-exclusive, worldwide, royalty-free patent +license under Licensed Patents to make, use, sell, offer to sell, +import and otherwise transfer the Contribution of such Contributor, +if any, in source code and object code form. This patent license +shall apply to the combination of the Contribution and the Program +if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to +be covered by the Licensed Patents. The patent license shall +not apply to any other combinations which include the Contribution. +No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants +the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe +the patent or other intellectual property rights of any other +entity. Each Contributor disclaims any liability to Recipient +for claims brought by any other entity based on infringement +of intellectual property rights or otherwise. As a condition +to exercising the rights and licenses granted hereunder, each +Recipient hereby assumes sole responsibility to secure any other +intellectual property rights needed, if any. For example, if +a third party patent license is required to allow Recipient to +distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient +copyright rights in its Contribution, if any, to grant the copyright +license set forth in this Agreement. +3. REQUIREMENTS +A Contributor may choose to distribute the Program in object +code form under its own license agreement, provided that: +a) it complies with the terms and conditions of this Agreement; +and +b) its license agreement: +i) effectively disclaims on behalf of all Contributors all warranties +and conditions, express and implied, including warranties or +conditions of title and non-infringement, and implied warranties +or conditions of merchantability and fitness for a particular +purpose; +ii) effectively excludes on behalf of all Contributors all liability +for damages, including direct, indirect, special, incidental +and consequential damages, such as lost profits; +iii) states that any provisions which differ from this Agreement +are offered by that Contributor alone and not by any other party; +and +iv) states that source code for the Program is available from +such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for +software exchange. +When the Program is made available in source code form: +a) it must be made available under this Agreement; and +b) a copy of this Agreement must be included with each copy of +the Program. +Contributors may not remove or alter any copyright notices contained +within the Program. +Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution. +4. COMMERCIAL DISTRIBUTION +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While +this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any +losses, damages and costs (collectively "Losses") arising from +claims, lawsuits and other legal actions brought by a third party +against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection +with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any +claims or Losses relating to any actual or alleged intellectual +property infringement. In order to qualify, an Indemnified Contributor +must: a) promptly notify the Commercial Contributor in writing +of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense +and any related settlement negotiations. The Indemnified Contributor +may participate in any such claim at its own expense. +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have +to defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any +other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. +5. NO WARRANTY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM +IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with +its exercise of rights under this Agreement , including but not +limited to the risks and costs of program errors, compliance +with applicable laws, damage to or loss of data, programs or +equipment, and unavailability or interruption of operations. +6. DISCLAIMER OF LIABILITY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE +OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGES. +7. GENERAL +If any provision of this Agreement is invalid or unenforceable +under applicable law, it shall not affect the validity or enforceability +of the remainder of the terms of this Agreement, and without +further action by the parties hereto, such provision shall be +reformed to the minimum extent necessary to make such provision +valid and enforceable. +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging +that the Program itself (excluding combinations of the Program +with other software or hardware) infringes such Recipient's patent(s), +then such Recipient's rights granted under Section 2(b) shall +terminate as of the date such litigation is filed. +All Recipient's rights under this Agreement shall terminate if +it fails to comply with any of the material terms or conditions +of this Agreement and does not cure such failure in a reasonable +period of time after becoming aware of such noncompliance. If +all Recipient's rights under this Agreement terminate, Recipient +agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under +this Agreement and any licenses granted by Recipient relating +to the Program shall continue and survive. +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted +and may only be modified in the following manner. The Agreement +Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other +than the Agreement Steward has the right to modify this Agreement. +The Eclipse Foundation is the initial Agreement Steward. The +Eclipse Foundation may assign the responsibility to serve as +the Agreement Steward to a suitable separate entity. Each new +version of the Agreement will be given a distinguishing version +number. The Program (including Contributions) may always be distributed +subject to the version of the Agreement under which it was received. +In addition, after a new version of the Agreement is published, +Contributor may elect to distribute the Program (including its +Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights +or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under +this Agreement are reserved. +This Agreement is governed by the laws of the State of New York +and the intellectual property laws of the United States of America. +No party to this Agreement will bring a legal action under this +Agreement more than one year after the cause of action arose. +Each party waives its rights to a jury trial in any resulting +litigation. + </license> + + <plugin + id="org.eclipse.zest.examples.cloudio" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.zest.cloudio" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + +</feature> diff --git a/org.eclipse.zest.examples.cloudio.feature/pom.xml b/org.eclipse.zest.examples.cloudio.feature/pom.xml new file mode 100644 index 0000000..98d0f1f --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.feature/pom.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.eclipse.zest.cloudio</groupId> + <version>2.0.0-SNAPSHOT</version> + <artifactId>parent</artifactId> + <relativePath>../org.eclipse.zest.examples.cloudio.build</relativePath> + </parent> + <groupId>org.eclipse.zest.cloudio</groupId> + <artifactId>org.eclipse.zest.examples.cloudio.feature</artifactId> + <version>2.0.0-SNAPSHOT</version> + <packaging>eclipse-feature</packaging> +</project>
\ No newline at end of file diff --git a/org.eclipse.zest.examples.cloudio.rcp/.project b/org.eclipse.zest.examples.cloudio.rcp/.project new file mode 100644 index 0000000..dfe707b --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.rcp/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.zest.examples.cloudio.rcp</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/org.eclipse.zest.examples.cloudio.rcp/org.eclipse.zest.examples.cloudio.rcp.product b/org.eclipse.zest.examples.cloudio.rcp/org.eclipse.zest.examples.cloudio.rcp.product new file mode 100644 index 0000000..0201ba0 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.rcp/org.eclipse.zest.examples.cloudio.rcp.product @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?pde version="3.5"?> + +<product name="Cloudio" uid="org.eclipse.zest.examples.cloudio.rcp.product" id="org.eclipse.zest.examples.cloudio.product" application="org.eclipse.zest.examples.cloudio.application" version="2.0.0.qualifier" useFeatures="true" includeLaunchers="true"> + + <aboutInfo> + <image path="eclipse_lg.gif"/> + <text> + %productBlurb + </text> + </aboutInfo> + + <configIni use="default"> + </configIni> + + <launcherArgs> + <programArgs>-consoleLog</programArgs> + <vmArgs>-Xms40m -Xmx256m</vmArgs> + <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts -Xdock:icon=../Resources/Eclipse.icns -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts</vmArgsMac> + </launcherArgs> + + <windowImages i16="eclipse.gif" i32="eclipse32.gif" i48="eclipse48.gif" i64="eclipse.png" i128="eclipse32.png"/> + + <splash + startupProgressRect="0,280,455,15" + startupMessageRect="7,220,441,20" + startupForegroundColor="C8D5EA" /> + <launcher> + <solaris/> + <win useIco="false"> + <bmp/> + </win> + </launcher> + + <vm> + <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6</linux> + <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6</macos> + <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6</windows> + </vm> + + <plugins> + </plugins> + + <features> + <feature id="org.eclipse.zest.examples.cloudio.feature" version="2.0.0.qualifier"/> + <feature id="org.eclipse.rcp"/> + </features> + + <configurations> + <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" /> + <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" /> + <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="1" /> + <plugin id="org.eclipse.osgi" autoStart="true" startLevel="-1" /> + </configurations> + +</product> diff --git a/org.eclipse.zest.examples.cloudio.rcp/plugin_customization.ini b/org.eclipse.zest.examples.cloudio.rcp/plugin_customization.ini new file mode 100644 index 0000000..333fab9 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.rcp/plugin_customization.ini @@ -0,0 +1 @@ +org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP = true diff --git a/org.eclipse.zest.examples.cloudio.rcp/pom.xml b/org.eclipse.zest.examples.cloudio.rcp/pom.xml new file mode 100644 index 0000000..08398f0 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio.rcp/pom.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>parent</artifactId> + <groupId>org.eclipse.zest.cloudio</groupId> + <version>2.0.0-SNAPSHOT</version> + <relativePath>../org.eclipse.zest.examples.cloudio.build</relativePath> + </parent> + <groupId>org.eclipse.zest.cloudio</groupId> + <version>2.0.0-SNAPSHOT</version> + <artifactId>org.eclipse.zest.examples.cloudio.rcp</artifactId> + <packaging>eclipse-repository</packaging> + + <build> + <plugins> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-p2-publisher-plugin</artifactId> + <version>${tycho-version}</version> + <configuration> + <publishArtifacts>true</publishArtifacts> + </configuration> + </plugin> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-p2-director-plugin</artifactId> + <version>${tycho-version}</version> + <executions> + <execution> + <id>materialize-products</id> + <goals> + <goal>materialize-products</goal> + </goals> + </execution> + <execution> + <id>archive-products</id> + <goals> + <goal>archive-products</goal> + </goals> + </execution> + </executions> + <configuration> + <products> + <product> + <id>org.eclipse.zest.examples.cloudio.rcp.product</id> + </product> + </products> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/org.eclipse.zest.examples.cloudio/.classpath b/org.eclipse.zest.examples.cloudio/.classpath new file mode 100644 index 0000000..fbb14bd --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src/main/java"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.zest.examples.cloudio/.project b/org.eclipse.zest.examples.cloudio/.project new file mode 100644 index 0000000..c3e2d8d --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.zest.examples.cloudio</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/org.eclipse.zest.examples.cloudio/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.zest.examples.cloudio/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..b83af5d --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Fri Jun 03 11:03:42 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.eclipse.zest.examples.cloudio/META-INF/MANIFEST.MF b/org.eclipse.zest.examples.cloudio/META-INF/MANIFEST.MF new file mode 100644 index 0000000..c28279c --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/META-INF/MANIFEST.MF @@ -0,0 +1,12 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Cloudio RCP Application +Bundle-SymbolicName: org.eclipse.zest.examples.cloudio;singleton:=true +Bundle-Version: 2.0.0.qualifier +Bundle-Activator: org.eclipse.zest.examples.cloudio.application.ui.CloudioApplicationPlugin +Require-Bundle: org.eclipse.ui, + org.eclipse.ui.views, + org.eclipse.core.runtime;bundle-version="3.6.0", + org.eclipse.zest.cloudio;bundle-version="2.0.0" +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 diff --git a/org.eclipse.zest.examples.cloudio/build.properties b/org.eclipse.zest.examples.cloudio/build.properties new file mode 100644 index 0000000..b774e9c --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.eclipse.zest.examples.cloudio/plugin.xml b/org.eclipse.zest.examples.cloudio/plugin.xml new file mode 100644 index 0000000..2bac2b8 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/plugin.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.4"?> +<plugin> + <extension + point="org.eclipse.ui.views"> + <view + class="org.eclipse.zest.examples.cloudio.application.ui.TagCloudViewPart" + id="org.eclipse.zest.cloudio.sample.tagcloud" + name="Tag Cloud View" + restorable="true"> + </view> + </extension> + <extension + point="org.eclipse.ui.actionSets"> + <actionSet + label="File Actions" + visible="true" + id="file.actions"> + <action + label="Export Image" + class="org.eclipse.zest.examples.cloudio.application.actions.ExportImageAction" + tooltip="Export image" + menubarPath="file/additions" + id="org.eclipse.zest.cloudio.export"> + </action> + <action + label="Load Stopwords" + class="org.eclipse.zest.examples.cloudio.application.actions.LoadStopWordsAction" + tooltip="Load stop word list" + menubarPath="file/additions" + id="org.eclipse.zest.cloudio.loadwords"> + </action> + <action + label="Load File" + class="org.eclipse.zest.examples.cloudio.application.actions.LoadFileAction" + tooltip="Load a new File" + menubarPath="file/additions" + id="org.eclipse.zest.cloudio.loadfile"> + </action> + </actionSet> + <actionSet + id="edit.actions" + label="Edit Actions" + visible="true"> + <action + class="org.eclipse.zest.examples.cloudio.application.actions.ZoomInAction" + id="org.eclipse.zest.cloudio.zoomin" + label="Zoom In" + menubarPath="edit/zoom" + style="push"> + </action> + <action + class="org.eclipse.zest.examples.cloudio.application.actions.ZoomOutAction" + id="org.eclipse.zest.cloudio.zoomout" + label="Zoom Out" + menubarPath="edit/zoom" + style="push"> + </action> + <action + class="org.eclipse.zest.examples.cloudio.application.actions.ZoomResetAction" + id="org.eclipse.zest.cloudio.zoomreset" + label="100 %" + menubarPath="edit/zoom" + style="push"> + </action> + <action + class="org.eclipse.zest.examples.cloudio.application.actions.ZoomFitAction" + id="org.eclipse.zest.cloudio.zoomfit" + label="Fit Window" + menubarPath="edit/zoom" + style="push"> + </action> + <action + class="org.eclipse.zest.examples.cloudio.application.actions.DeselectAllAction" + id="org.eclipse.zest.cloudio.deselectall" + label="Clear Selection" + menubarPath="edit/select" + style="push"> + </action> + <action + class="org.eclipse.zest.examples.cloudio.application.actions.SelectAllAction" + id="org.eclipse.zest.cloudio.selectall" + label="Select All" + menubarPath="edit/select" + style="push"> + </action> + </actionSet> + </extension> + +<extension + id="application" + name="Tag Cloud" + point="org.eclipse.core.runtime.applications"> + <application + cardinality="singleton-global" + thread="main" + visible="true"> + <run + class="org.eclipse.zest.examples.cloudio.application.Application"> + </run> + </application> + </extension> + <extension + point="org.eclipse.ui.perspectives"> + <perspective + class="org.eclipse.zest.examples.cloudio.application.PerspectiveFactory" + id="org.eclipse.zest.cloudio.rcp.perspective" + name="cloudPerspective"> + </perspective> + </extension> + <extension + id="product" + point="org.eclipse.core.runtime.products"> + <product + application="org.eclipse.zest.examples.cloudio.application" + name="Cloudio"> + <property + name="windowImages" + value="eclipse.gif,eclipse32.gif,eclipse48.gif,eclipse.png,eclipse32.png"> + </property> + <property + name="aboutText" + value="%productBlurb"> + </property> + <property + name="aboutImage" + value="eclipse_lg.gif"> + </property> + <property + name="startupForegroundColor" + value="C8D5EA"> + </property> + <property + name="startupProgressRect" + value="0,280,455,15"> + </property> + <property + name="startupMessageRect" + value="7,220,441,20"> + </property> + <property + name="preferenceCustomization" + value="plugin_customization.ini"> + </property> + <property + name="appName" + value="Cloudio"> + </property> + </product> + </extension> +</plugin> diff --git a/org.eclipse.zest.examples.cloudio/pom.xml b/org.eclipse.zest.examples.cloudio/pom.xml new file mode 100644 index 0000000..27e8745 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/pom.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>parent</artifactId> + <groupId>org.eclipse.zest.cloudio</groupId> + <version>2.0.0-SNAPSHOT</version> + <relativePath>../org.eclipse.zest.examples.cloudio.build</relativePath> + </parent> + <groupId>org.eclipse.zest.cloudio</groupId> + <artifactId>org.eclipse.zest.examples.cloudio</artifactId> + <version>2.0.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> +</project> diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/Application.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/Application.java new file mode 100644 index 0000000..be1bd04 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/Application.java @@ -0,0 +1,56 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application; + +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; + +/** + * + * @author sschwieb + * + */ +public class Application implements IApplication { + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext) + */ + public Object start(IApplicationContext context) { + Display display = PlatformUI.createDisplay(); + try { + int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor()); + if (returnCode == PlatformUI.RETURN_RESTART) { + return IApplication.EXIT_RESTART; + } + return IApplication.EXIT_OK; + } finally { + display.dispose(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#stop() + */ + public void stop() { + final IWorkbench workbench = PlatformUI.getWorkbench(); + if (workbench == null) + return; + final Display display = workbench.getDisplay(); + display.syncExec(new Runnable() { + public void run() { + if (!display.isDisposed()) + workbench.close(); + } + }); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationActionBarAdvisor.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationActionBarAdvisor.java new file mode 100644 index 0000000..7786280 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationActionBarAdvisor.java @@ -0,0 +1,72 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application; + +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.GroupMarker; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.zest.examples.cloudio.application.actions.AboutAction; + +/** + * + * @author sschwieb + * + */ +public class ApplicationActionBarAdvisor extends ActionBarAdvisor { + + private IWorkbenchAction exitAction; + private IWorkbenchAction aboutAction; + + + public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) { + super(configurer); + } + + protected void makeActions(final IWorkbenchWindow window) { + exitAction = ActionFactory.QUIT.create(window); + AboutAction about = new AboutAction(); + register(about); + register(exitAction); + this.aboutAction = about; + + } + + + @Override + protected void fillMenuBar(IMenuManager menuBar) { + MenuManager fileMenu = new MenuManager("&File", IWorkbenchActionConstants.M_FILE); + menuBar.add(fileMenu); + ActionContributionItem aboutActionItem = new ActionContributionItem(aboutAction); + fileMenu.add(aboutActionItem); + fileMenu.add(new Separator()); + fileMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); + fileMenu.add(new Separator()); + MenuManager editMenu = new MenuManager("&Edit", IWorkbenchActionConstants.M_EDIT); + editMenu.add(new GroupMarker("select")); + editMenu.add(new Separator()); + editMenu.add(new GroupMarker("zoom")); + menuBar.add(editMenu); + super.fillMenuBar(menuBar); + ActionContributionItem exitActionItem = new ActionContributionItem(exitAction); + fileMenu.add(exitActionItem); + if(System.getProperty("os.name").contains("Mac")) { + aboutActionItem.setVisible(false); + exitActionItem.setVisible(false); + } + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationWorkbenchAdvisor.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationWorkbenchAdvisor.java new file mode 100644 index 0000000..16fdcd5 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationWorkbenchAdvisor.java @@ -0,0 +1,51 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application; + +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchAdvisor; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +/** + * + * @author sschwieb + * + */ +public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor { + + @Override + public String getInitialWindowPerspectiveId() { + return "org.eclipse.zest.cloudio.rcp.perspective"; + } + + @Override + public void initialize(IWorkbenchConfigurer configurer) { + super.initialize(configurer); + } + + + @Override + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( + IWorkbenchWindowConfigurer configurer) { + return new ApplicationWorkbenchWindowAdvisor(configurer); + } + + @Override + public void fillActionBars(IWorkbenchWindow window, + IActionBarConfigurer configurer, int flags) { + + } + + + + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationWorkbenchWindowAdvisor.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationWorkbenchWindowAdvisor.java new file mode 100644 index 0000000..381479c --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ApplicationWorkbenchWindowAdvisor.java @@ -0,0 +1,41 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.application.ActionBarAdvisor; +import org.eclipse.ui.application.IActionBarConfigurer; +import org.eclipse.ui.application.IWorkbenchWindowConfigurer; +import org.eclipse.ui.application.WorkbenchWindowAdvisor; + +/** + * + * @author sschwieb + * + */ +public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { + + public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { + super(configurer); + } + + public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) { + return new ApplicationActionBarAdvisor(configurer); + } + + public void preWindowOpen() { + IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); + configurer.setInitialSize(new Point(900, 700)); + configurer.setShowCoolBar(false); + configurer.setShowProgressIndicator(false); + configurer.setTitle("Cloudio"); + configurer.setShowStatusLine(false); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/PerspectiveFactory.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/PerspectiveFactory.java new file mode 100644 index 0000000..da48ce8 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/PerspectiveFactory.java @@ -0,0 +1,28 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application; + +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; + +/** + * + * @author sschwieb + * + */ +public class PerspectiveFactory implements IPerspectiveFactory { + + @Override + public void createInitialLayout(IPageLayout layout) { + layout.addStandaloneView("org.eclipse.zest.cloudio.sample.tagcloud", false, IPageLayout.TOP, 0.95f, layout.getEditorArea()); + layout.setFixed(true); + layout.setEditorAreaVisible(false); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/about/AboutDialog.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/about/AboutDialog.java new file mode 100644 index 0000000..e415af3 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/about/AboutDialog.java @@ -0,0 +1,135 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.about; + +import java.awt.GraphicsEnvironment; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.FontData; +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.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.zest.cloudio.TagCloud; +import org.eclipse.zest.cloudio.Word; +import org.eclipse.zest.cloudio.layout.DefaultLayouter; + +/** + * + * @author sschwieb + * + */ +public class AboutDialog extends Dialog { + + private static final int RE_LAYOUT = 2; + private TagCloud tc; + + public AboutDialog(Shell parentShell) { + super(parentShell); + setBlockOnOpen(false); + } + + @Override + protected Control createDialogArea(Composite parent) { + parent.setLayout(new GridLayout()); + tc = new TagCloud(parent, SWT.NONE) { + + public Rectangle getClientArea() { + return new Rectangle(0, 0, 400, 330); + }; + + }; + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + data.heightHint=330; + data.widthHint=400; + tc.setLayoutData(data); + tc.setMaxFontSize(50); + tc.setMinFontSize(15); + tc.setLayouter(new DefaultLayouter(5, 0)); + List<Word> values = new ArrayList<Word>(); + String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + Color[] colors = new Color[5]; + colors[0] = Display.getDefault().getSystemColor(SWT.COLOR_DARK_CYAN); + colors[1] = Display.getDefault().getSystemColor(SWT.COLOR_DARK_GREEN); + colors[2] = Display.getDefault().getSystemColor(SWT.COLOR_DARK_MAGENTA); + colors[3] = Display.getDefault().getSystemColor(SWT.COLOR_DARK_YELLOW); + colors[4] = Display.getDefault().getSystemColor(SWT.COLOR_GRAY); + Word w = getWord("Cloudio", fontNames, colors); + w.weight=0.95; + w.angle=-35; + w.setColor(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + values.add(w); + w = getWord("Inspired by Wordle", fontNames, colors); + w.setColor(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + w.angle = (float) (Math.random() * 90); + if(Math.random() < 0.5) w.angle = -w.angle; + w.weight=0.2; + if(Math.random() < 0.5) w.angle = -w.angle; + values.add(w); + w = getWord("Used by " + System.getProperty("user.name"), fontNames, colors); + w.setColor(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); + w.weight = 0.2; + values.add(w); + for(int i = 0; i < 20; i++) { + w = getWord("Cloudio", fontNames, colors); + values.add(w); + w = getWord("Tag Cloud", fontNames, colors); + values.add(w); + } + tc.setWords(values, null); + Label l = new Label(parent, SWT.NONE); + l.setText("Written by Stephan Schwiebert, 2011"); + return tc; + } + + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, + true); + createButton(parent, RE_LAYOUT, "Do the inevitable...", false); + } + + @Override + protected void buttonPressed(int buttonId) { + if(buttonId == RE_LAYOUT) { + tc.layoutCloud(null, false); + } else { + super.buttonPressed(buttonId); + } + } + + private Word getWord(String string, String[] fontNames, Color[] colors) { + Word w = new Word(string); + w.setColor(colors[(int) (Math.random()*colors.length-1)]); + w.weight = Math.random()/2; + w.setFontData(getShell().getFont().getFontData()); + w.angle = (float) (Math.random() * 20); + if(Math.random() < 0.5) w.angle = -w.angle; + String name = fontNames[(int) (Math.random()*(fontNames.length-1))]; + for (FontData fd : w.getFontData()) { + fd.setName(name); + } + return w; + } + + @Override + public boolean close() { + tc.dispose(); + return super.close(); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/AboutAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/AboutAction.java new file mode 100644 index 0000000..b6ec6e6 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/AboutAction.java @@ -0,0 +1,39 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction; +import org.eclipse.zest.examples.cloudio.application.about.AboutDialog; + +/** + * + * @author sschwieb + * + */ +public class AboutAction extends Action implements IWorkbenchAction { + + public AboutAction() { + super.setId("about"); + setText("About"); + } + + @Override + public void run() { + AboutDialog dialog = new AboutDialog(Display.getCurrent().getActiveShell()); + dialog.open(); + } + + @Override + public void dispose() { + + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/AbstractTagCloudAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/AbstractTagCloudAction.java new file mode 100644 index 0000000..e1c2848 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/AbstractTagCloudAction.java @@ -0,0 +1,52 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.zest.cloudio.TagCloudViewer; +import org.eclipse.zest.examples.cloudio.application.ui.TagCloudViewPart; + +/** + * + * @author sschwieb + * + */ +public abstract class AbstractTagCloudAction implements IWorkbenchWindowActionDelegate { + + private Shell shell; + private TagCloudViewPart tcViewPart; + + + @Override + public void selectionChanged(IAction action, ISelection selection) {} + + @Override + public void dispose() {} + + @Override + public void init(IWorkbenchWindow window) { + this.shell = window.getShell(); + tcViewPart = (TagCloudViewPart) window.getActivePage().getActivePart(); + } + + public Shell getShell() { + return shell; + } + + + protected TagCloudViewer getViewer() { + return tcViewPart.getViewer(); + } + + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/DeselectAllAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/DeselectAllAction.java new file mode 100644 index 0000000..ad49298 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/DeselectAllAction.java @@ -0,0 +1,27 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.StructuredSelection; + +/** + * + * @author sschwieb + * + */ +public class DeselectAllAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + StructuredSelection selection = new StructuredSelection(); + getViewer().setSelection(selection); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ExportImageAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ExportImageAction.java new file mode 100644 index 0000000..2c4dead --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ExportImageAction.java @@ -0,0 +1,48 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import java.io.File; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.widgets.FileDialog; + +/** + * + * @author sschwieb + * + */ +public class ExportImageAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); + dialog.setFileName("Cloud.png"); + dialog.setText("Export PNG image to..."); + String destFile = dialog.open(); + if(destFile == null) return; + File f = new File(destFile); + if(f.exists()) { + boolean confirmed = MessageDialog.openConfirm(getShell(), "File already exists", "The file '" + f.getName() + "' does already exist. Do you want to override it?"); + if(!confirmed) return; + } + ImageLoader il = new ImageLoader(); + try { + il.data = new ImageData[] {getViewer().getCloud().getImageData()}; + il.save(destFile, SWT.IMAGE_PNG); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/LoadFileAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/LoadFileAction.java new file mode 100644 index 0000000..820a2d2 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/LoadFileAction.java @@ -0,0 +1,53 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.zest.cloudio.TagCloudViewer; +import org.eclipse.zest.examples.cloudio.application.data.Type; +import org.eclipse.zest.examples.cloudio.application.data.TypeCollector; + +/** + * + * @author sschwieb + * + */ +public class LoadFileAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); + + dialog.setText("Select text file..."); + String sourceFile = dialog.open(); + if(sourceFile == null) return; + ProgressMonitorDialog pd = new ProgressMonitorDialog(getShell()); + try { + List<Type> types = TypeCollector.getData(new File(sourceFile), "UTF-8"); + pd.setBlockOnOpen(false); + pd.open(); + pd.getProgressMonitor().beginTask("Generating cloud...", 200); + TagCloudViewer viewer = getViewer(); + viewer.setInput(types, pd.getProgressMonitor()); + viewer.getCloud().layoutCloud(pd.getProgressMonitor(), false); + } catch (IOException e) { + e.printStackTrace(); + } finally { + pd.close(); + } + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/LoadStopWordsAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/LoadStopWordsAction.java new file mode 100644 index 0000000..8f19522 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/LoadStopWordsAction.java @@ -0,0 +1,32 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.zest.examples.cloudio.application.data.TypeCollector; + +/** + * + * @author sschwieb + * + */ +public class LoadStopWordsAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); + dialog.setText("Select a stopwor file, containing one word per line..."); + String sourceFile = dialog.open(); + if(sourceFile == null) return; + TypeCollector.setStopwords(sourceFile); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/SelectAllAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/SelectAllAction.java new file mode 100644 index 0000000..4b3f95c --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/SelectAllAction.java @@ -0,0 +1,29 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import java.util.List; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.StructuredSelection; + +/** + * + * @author sschwieb + * + */ +public class SelectAllAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + StructuredSelection selection = new StructuredSelection((List<?>)getViewer().getInput()); + getViewer().setSelection(selection); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomFitAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomFitAction.java new file mode 100644 index 0000000..17c3b45 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomFitAction.java @@ -0,0 +1,25 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; + +/** + * + * @author sschwieb + * + */ +public class ZoomFitAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + getViewer().zoomFit(); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomInAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomInAction.java new file mode 100644 index 0000000..554f7ca --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomInAction.java @@ -0,0 +1,25 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; + +/** + * + * @author sschwieb + * + */ +public class ZoomInAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + getViewer().zoomIn(); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomOutAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomOutAction.java new file mode 100644 index 0000000..1ec23c0 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomOutAction.java @@ -0,0 +1,25 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; + +/** + * + * @author sschwieb + * + */ +public class ZoomOutAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + getViewer().zoomOut(); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomResetAction.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomResetAction.java new file mode 100644 index 0000000..a2d9b73 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/actions/ZoomResetAction.java @@ -0,0 +1,25 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.actions; + +import org.eclipse.jface.action.IAction; + +/** + * + * @author sschwieb + * + */ +public class ZoomResetAction extends AbstractTagCloudAction { + + @Override + public void run(IAction action) { + getViewer().zoomReset(); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/data/Type.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/data/Type.java new file mode 100644 index 0000000..b571465 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/data/Type.java @@ -0,0 +1,34 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.data; + +/** + * + * @author sschwieb + * + */ +public class Type { + + private String string; + private int occurrences; + + public Type(String string, int occurrences) { + this.string = string; + this.occurrences = occurrences; + } + + public String getString() { + return string; + } + + public int getOccurrences() { + return occurrences; + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/data/TypeCollector.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/data/TypeCollector.java new file mode 100644 index 0000000..1a82350 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/data/TypeCollector.java @@ -0,0 +1,111 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.data; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.text.BreakIterator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * + * @author sschwieb + * + */ +public class TypeCollector { + + private static String stopWords; + + public static List<Type> getData(File file, String encoding) throws IOException { + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + BufferedReader br = new BufferedReader(new InputStreamReader(bis, encoding)); + StringBuffer text = new StringBuffer(); + String s; + while((s = br.readLine()) != null) { + text.append(s + "\n"); + } + br.close(); + Set<String> stops = new HashSet<String>(); + if(stopWords != null) { + bis = new BufferedInputStream(new FileInputStream(stopWords)); + br = new BufferedReader(new InputStreamReader(bis, encoding)); + while((s = br.readLine()) != null) { + stops.add(s.toLowerCase().trim()); + } + br.close(); + } + BreakIterator iterator = BreakIterator.getWordInstance(Locale.getDefault()); + String txt = text.toString(); + iterator.setText(txt); + final Map<String, Integer> strings = new HashMap<String, Integer>(); + int boundary = iterator.first(); + int lastBoundary = iterator.first(); + while (boundary != BreakIterator.DONE) { + boundary = iterator.next(); + if (boundary != -1) { + String string = txt.substring(lastBoundary, boundary).trim(); + if (string.length() != 0) { + if (!Character.isLetter(string.charAt(string.length() - 1))) { + string = string.substring(0, string.length() - 1); + } + if (stops.contains(string.toLowerCase()) || string.trim().length() <= 1) { + lastBoundary = boundary; + continue; + } + Integer count = strings.get(string); + if (count == null) { + strings.put(string, 1); + } else { + count = count + 1; + strings.put(string, count); + } + } + } + lastBoundary = boundary; + } + return getMostImportantTypes(strings); + } + + private static List<Type> getMostImportantTypes(final Map<String, Integer> strings) { + List<Type> types = new ArrayList<Type>(); + Iterator<Entry<String, Integer>> iterator = strings.entrySet().iterator(); + while(iterator.hasNext()) { + Entry<String, Integer> entry = iterator.next(); + Type type = new Type(entry.getKey(), entry.getValue()); + types.add(type); + } + List<Type> sorted = new ArrayList<Type>(types); + Collections.sort(sorted, new Comparator<Type>() { + + @Override + public int compare(Type o1, Type o2) { + return o2.getOccurrences() - o1.getOccurrences(); + } + }); + return sorted; + } + + public static void setStopwords(String sourceFile) { + stopWords = sourceFile; + } +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/CloudioApplicationPlugin.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/CloudioApplicationPlugin.java new file mode 100644 index 0000000..2f52316 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/CloudioApplicationPlugin.java @@ -0,0 +1,61 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.ui; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + + +/** + * + * @author sschwieb + * + */ +public class CloudioApplicationPlugin extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.examples.zest.cloudio"; //$NON-NLS-1$ + + // The shared instance + private static CloudioApplicationPlugin plugin; + + /** + * The constructor + */ + public CloudioApplicationPlugin() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static CloudioApplicationPlugin getDefault() { + return plugin; + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/TagCloudViewPart.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/TagCloudViewPart.java new file mode 100644 index 0000000..5bb8193 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/TagCloudViewPart.java @@ -0,0 +1,230 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.zest.cloudio.CloudOptionsComposite; +import org.eclipse.zest.cloudio.TagCloud; +import org.eclipse.zest.cloudio.TagCloudViewer; +import org.eclipse.zest.cloudio.layout.DefaultLayouter; +import org.eclipse.zest.cloudio.layout.ILayouter; +import org.eclipse.zest.examples.cloudio.application.data.Type; + +/** + * + * @author sschwieb + * + */ +public class TagCloudViewPart extends ViewPart { + + private TagCloudViewer viewer; + private TypeLabelProvider labelProvider; + private CloudOptionsComposite options; + private ILayouter layouter; + + public TagCloudViewPart() { + } + + @Override + public void createPartControl(Composite parent) { + SashForm sash = new SashForm(parent, SWT.HORIZONTAL); + sash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + Composite cloudComp = new Composite(sash, SWT.NONE); + cloudComp.setLayout(new GridLayout()); + cloudComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + TagCloud cloud = new TagCloud(cloudComp, SWT.HORIZONTAL | SWT.VERTICAL); + cloud.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + viewer = new TagCloudViewer(cloud); + + layouter = new DefaultLayouter(20, 10); + //layouter = new CharacterLayouter(20,10); + viewer.setLayouter(layouter); + labelProvider = new TypeLabelProvider(); + //labelProvider = new CharacterLabelProvider(); + viewer.setLabelProvider(labelProvider); + viewer.setContentProvider(new IStructuredContentProvider() { + + @Override + public void inputChanged(Viewer v, Object oldInput, Object newInput) { + List<?> list = (List<?>) newInput; + if(list == null || list.size() == 0) return; + labelProvider.setMaxOccurrences(((Type)list.get(0)).getOccurrences()); + int minIndex =Math.min(list.size()-1, viewer.getMaxWords()); + labelProvider.setMinOccurrences(((Type)list.get(minIndex)).getOccurrences()); + } + + @Override + public void dispose() { + + } + + @Override + public Object[] getElements(Object inputElement) { + return ((List<?>)inputElement).toArray(); + } + }); + createSideTab(sash); + + cloud.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + viewer.getCloud().addControlListener(new ControlListener() { + + @Override + public void controlResized(ControlEvent e) { + viewer.getCloud().zoomFit(); + } + + @Override + public void controlMoved(ControlEvent e) {} + }); + ArrayList<Type> types = new ArrayList<Type>(); + types.add(new Type("Cloudio", 220)); + types.add(new Type("Cloudio", 150)); + types.add(new Type("Cloudio", 100)); + types.add(new Type("No data available", 150)); + int size = 55; + for(int i = 0; i < 50; i++) { + types.add(new Type("Tag Cloud", size)); + size--; + } + viewer.getCloud().setMaxFontSize(100); + viewer.getCloud().setMinFontSize(15); + labelProvider.setColors(options.getColors()); + labelProvider.setFonts(options.getFonts()); + sash.setWeights(new int[] {72,28}); + viewer.setInput(types); + } + + private void createSideTab(SashForm form) { + Composite parent = new Composite(form, SWT.NONE); + parent.setLayout(new GridLayout()); + parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + options = new CloudOptionsComposite(parent, SWT.NONE, viewer) { + + protected Group addLayoutButtons(Composite parent) { + Group buttons = super.addLayoutButtons(parent); + + + Label l = new Label(buttons, SWT.NONE); + l.setText("X Axis Variation"); + final Combo xAxis = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + xAxis.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + xAxis.setItems(new String[] {"0", "10","20","30","40","50", "60", "70", "80", "90", "100"}); + xAxis.select(2); + xAxis.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = xAxis.getItem(xAxis.getSelectionIndex()); + layouter.setOption(DefaultLayouter.X_AXIS_VARIATION, Integer.parseInt(item)); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + l = new Label(buttons, SWT.NONE); + l.setText("Y Axis Variation"); + final Combo yAxis = new Combo(buttons, SWT.DROP_DOWN | SWT.READ_ONLY); + yAxis.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + yAxis.setItems(new String[] {"0", "10","20","30","40","50", "60", "70", "80", "90", "100"}); + yAxis.select(1); + yAxis.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String item = yAxis.getItem(yAxis.getSelectionIndex()); + layouter.setOption(DefaultLayouter.Y_AXIS_VARIATION, Integer.parseInt(item)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + + Button run = new Button(buttons, SWT.NONE); + run.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + run.setText("Re-Position"); + run.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + final ProgressMonitorDialog dialog = new ProgressMonitorDialog(viewer.getControl().getShell()); + dialog.setBlockOnOpen(false); + dialog.open(); + dialog.getProgressMonitor().beginTask("Layouting tag cloud...", 100); + viewer.reset(dialog.getProgressMonitor(),false); + dialog.close(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + Button layout = new Button(buttons, SWT.NONE); + layout.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + layout.setText("Re-Layout"); + layout.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + ProgressMonitorDialog dialog = new ProgressMonitorDialog(viewer.getControl().getShell()); + dialog.setBlockOnOpen(false); + dialog.open(); + dialog.getProgressMonitor().beginTask("Layouting tag cloud...", 200); + viewer.setInput(viewer.getInput(), dialog.getProgressMonitor()); + viewer.reset(dialog.getProgressMonitor(),false); + dialog.close(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) {} + }); + return buttons; + }; + + }; + GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); + options.setLayoutData(gd); + } + + + @Override + public void setFocus() { + viewer.getCloud().setFocus(); + } + + @Override + public void dispose() { + viewer.getCloud().dispose(); + labelProvider.dispose(); + } + + public TagCloudViewer getViewer() { + return viewer; + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/TypeLabelProvider.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/TypeLabelProvider.java new file mode 100644 index 0000000..5d89331 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/TypeLabelProvider.java @@ -0,0 +1,143 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.ui; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.eclipse.jface.viewers.BaseLabelProvider; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.eclipse.zest.cloudio.IEditableCloudLabelProvider; +import org.eclipse.zest.examples.cloudio.application.data.Type; + +/** + * + * @author sschwieb + * + */ +public class TypeLabelProvider extends BaseLabelProvider implements + IEditableCloudLabelProvider { + + private double maxOccurrences; + private double minOccurrences; + + private Map<Object, Color> colors = new HashMap<Object, Color>(); + private Map<Object, FontData[]> fonts = new HashMap<Object, FontData[]>(); + private Random random = new Random(); + protected List<Color> colorList; + protected List<Font> fontList; + protected List<Float> angles; + + public TypeLabelProvider() { + colorList = new ArrayList<Color>(); + fontList = new ArrayList<Font>(); + angles = new ArrayList<Float>(); + angles.add(0F); + } + + @Override + public String getLabel(Object element) { + return ((Type)element).getString(); + } + + @Override + public double getWeight(Object element) { + double count = Math.log(((Type)element).getOccurrences() - minOccurrences+1); + count /=(Math.log(maxOccurrences)); + return count; + } + + @Override + public Color getColor(Object element) { + Color color = colors.get(element); + if(color == null) { + color = colorList.get(random.nextInt(colorList.size())); + colors.put(element, color); + } + return color; + } + + public FontData[] getFontData(Object element) { + FontData[] data = fonts.get(element); + if(data == null) { + data = fontList.get(random.nextInt(fontList.size())).getFontData(); + fonts.put(element, data); + } + return data; + } + + public void setMaxOccurrences(int occurrences) { + this.maxOccurrences = occurrences; + } + + public void setMinOccurrences(int occurrences) { + this.minOccurrences = occurrences; + } + + @Override + public void dispose() { + for (Color color : colorList) { + color.dispose(); + } + for (Font font : fontList) { + font.dispose(); + } + } + + public void setAngles(List<Float> angles) { + this.angles = angles; + } + + @Override + public float getAngle(Object element) { + float angle = angles.get(random.nextInt(angles.size())); + return angle; + } + + public void setColors(List<RGB> newColors) { + if(newColors.isEmpty()) return; + for (Color color : colorList) { + color.dispose(); + } + colorList.clear(); + colors.clear(); + for (RGB color : newColors) { + Color c = new Color(Display.getDefault(), color); + colorList.add(c); + } + } + + public void setFonts(List<FontData> newFonts) { + if(newFonts.isEmpty()) return; + for (Font font : fontList) { + font.dispose(); + } + fontList.clear(); + fonts.clear(); + for (FontData data : newFonts) { + Font f = new Font(Display.getDefault(), data); + fontList.add(f); + } + } + + @Override + public String getToolTip(Object element) { + return getLabel(element); + } + + + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/customization/CharacterLabelProvider.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/customization/CharacterLabelProvider.java new file mode 100644 index 0000000..039fee6 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/customization/CharacterLabelProvider.java @@ -0,0 +1,38 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.ui.customization; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.zest.examples.cloudio.application.data.Type; +import org.eclipse.zest.examples.cloudio.application.ui.TypeLabelProvider; + +/** + * An example to demonstrate how to modify a label provider + * @author sschwieb + * + */ +public class CharacterLabelProvider extends TypeLabelProvider { + + @Override + public Color getColor(Object element) { + Type t = (Type) element; + char firstChar = Character.toLowerCase(t.getString().charAt(0)); + if(firstChar < 'g') { + return colorList.get(2); + } + if(firstChar < 'm') { + return colorList.get(1); + } + if(firstChar < 's') { + return colorList.get(0); + } + return colorList.get(3); + } + +} diff --git a/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/customization/CharacterLayouter.java b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/customization/CharacterLayouter.java new file mode 100644 index 0000000..1225d60 --- a/dev/null +++ b/org.eclipse.zest.examples.cloudio/src/main/java/org/eclipse/zest/examples/cloudio/application/ui/customization/CharacterLayouter.java @@ -0,0 +1,47 @@ +/******************************************************************************* +* Copyright (c) 2011 Stephan Schwiebert. 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 +* <p/> +* Contributors: Stephan Schwiebert - initial API and implementation +*******************************************************************************/ +package org.eclipse.zest.examples.cloudio.application.ui.customization; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.zest.cloudio.Word; +import org.eclipse.zest.cloudio.layout.DefaultLayouter; + +/** + * An example to show how to modify a layouter + * @author sschwieb + * + */ +public class CharacterLayouter extends DefaultLayouter { + + public CharacterLayouter(int x, int y) { + super(x,y); + } + + public Point getInitialOffset(Word word, Rectangle cloudArea) { + Point parentOffsets = super.getInitialOffset(word, new Rectangle(cloudArea.x, cloudArea.y, cloudArea.width/4, cloudArea.height/4)); + char firstChar = Character.toLowerCase(word.string.charAt(0)); + int x=cloudArea.width/4; + int y = cloudArea.height/4; + if(firstChar < 's') { + x = 0; + y = 0; + } + if(firstChar < 'm') { + x = cloudArea.width/4; + y = 0; + } + if(firstChar < 'g') { + x = 0; + y = cloudArea.height/4; + } + return new Point(x+parentOffsets.x, y+parentOffsets.y); + } + +} diff --git a/org.eclipse.zest.feature/feature.xml b/org.eclipse.zest.feature/feature.xml index 9a7e301..eabb014 100644 --- a/org.eclipse.zest.feature/feature.xml +++ b/org.eclipse.zest.feature/feature.xml @@ -63,4 +63,11 @@ version="0.0.0" unpack="false"/> + <plugin + id="org.eclipse.zest.cloudio" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + </feature> diff --git a/org.eclipse.zest.source-feature/feature.xml b/org.eclipse.zest.source-feature/feature.xml index 2c985a5..ef4d45c 100644 --- a/org.eclipse.zest.source-feature/feature.xml +++ b/org.eclipse.zest.source-feature/feature.xml @@ -16,6 +16,13 @@ <license url="%licenseURL"> %license </license> + + <plugin + id="org.eclipse.zest.cloudio.source" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> <plugin id="org.eclipse.zest.core.source" diff --git a/org.eclipse.zest.tests/META-INF/MANIFEST.MF b/org.eclipse.zest.tests/META-INF/MANIFEST.MF index 570bc6b..73c4c11 100644 --- a/org.eclipse.zest.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.zest.tests/META-INF/MANIFEST.MF @@ -8,7 +8,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.zest.dot.ui;bundle-version="0.9.1", org.junit;bundle-version="4.8.1", - org.eclipse.zest.jface;bundle-version="2.0.0" + org.eclipse.zest.jface;bundle-version="2.0.0", + org.eclipse.zest.cloudio;bundle-version="2.0.0" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: org.eclipse.zest.tests.dot diff --git a/org.eclipse.zest.tests/pom.xml b/org.eclipse.zest.tests/pom.xml index 0762cee..63991dd 100644 --- a/org.eclipse.zest.tests/pom.xml +++ b/org.eclipse.zest.tests/pom.xml @@ -35,7 +35,7 @@ </os> </activation> <properties> - <vmargs>-Xmx512m -XX:MaxPermSize=256m -XstartOnFirstThread</vmargs> + <vmargs>-Xmx768m -XX:MaxPermSize=512m -XstartOnFirstThread</vmargs> </properties> </profile> </profiles> diff --git a/org.eclipse.zest.tests/src/org/eclipse/zest/tests/AllHeadlessTests.java b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/AllHeadlessTests.java index 8a02cb6..2d9e656 100644 --- a/org.eclipse.zest.tests/src/org/eclipse/zest/tests/AllHeadlessTests.java +++ b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/AllHeadlessTests.java @@ -8,6 +8,8 @@ *******************************************************************************/ package org.eclipse.zest.tests; +import org.eclipse.zest.tests.cloudio.TagCloudTests; +import org.eclipse.zest.tests.cloudio.TagCloudViewerTests; import org.eclipse.zest.tests.dot.DotExportSuite; import org.eclipse.zest.tests.dot.DotImportSuite; import org.junit.runner.RunWith; @@ -21,6 +23,7 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ GraphSelectionTests.class, GraphViewerTests.class, IFigureProviderTests.class, LayoutAlgorithmTests.class, - DotExportSuite.class, DotImportSuite.class }) + DotExportSuite.class, DotImportSuite.class, TagCloudTests.class, + TagCloudViewerTests.class }) public final class AllHeadlessTests { } diff --git a/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TagCloudTests.java b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TagCloudTests.java new file mode 100644 index 0000000..28543a4 --- a/dev/null +++ b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TagCloudTests.java @@ -0,0 +1,629 @@ +/******************************************************************************* + * Copyright (c) 2011 Stephan Schwiebert. 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 + * <p/> + * Contributors: Stephan Schwiebert - initial API and implementation + *******************************************************************************/ +package org.eclipse.zest.tests.cloudio; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import junit.framework.Assert; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.MouseWheelListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.zest.cloudio.TagCloud; +import org.eclipse.zest.cloudio.Word; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TagCloudTests { + + private Display display; + private boolean createdDisplay = false; + private Composite composite; + + @Before + public void setUp() throws Exception { + display = Display.getCurrent(); + if (display == null) { + display = new Display(); + createdDisplay = true; + } + composite = new Shell(display); + composite.setLayout(new FillLayout()); + } + + @After + public void tearDown() throws Exception { + composite.dispose(); + if (createdDisplay) { + display.dispose(); + } + } + + // Lifecycle: + + @Test(expected = IllegalArgumentException.class) + public void testConstructor_NullParent() { + new TagCloud(null, SWT.NONE); + } + + @Test + public void testConstructor_ValidParent() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Assert.assertNotNull(cloud); + } + + @Test + public void testDispose() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.dispose(); + Assert.assertTrue(cloud.isDisposed()); + } + + // Background Color: + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidBackgroundColor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setBackground(null); + } + + @Test + public void testSetValidBackgroundColor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Color color = Display.getCurrent().getSystemColor(SWT.COLOR_RED); + cloud.setBackground(color); + Assert.assertEquals(color, cloud.getBackground()); + } + + @Test + public void testDefaultBackgroundColor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Assert.assertNotNull(cloud.getBackground()); + } + + // Selection Color: + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidSelectionColor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setSelectionColor(null); + } + + @Test + public void testSetValidSelectionColor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Color color = Display.getCurrent().getSystemColor(SWT.COLOR_RED); + cloud.setSelectionColor(color); + Assert.assertEquals(color, cloud.getSelectionColor()); + } + + @Test + public void testDefaultSelectionColor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Assert.assertNotNull(cloud.getSelectionColor()); + } + + // Font Size: + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidMaxFontSize() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setMaxFontSize(0); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidMinFontSize() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setMinFontSize(0); + } + + @Test + public void testSetValidMaxFontSize() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + int size = cloud.getMaxFontSize() + 1; + cloud.setMaxFontSize(size * 2); + Assert.assertEquals(size * 2, cloud.getMaxFontSize()); + } + + @Test + public void testSetValidMinFontSize() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + int size = cloud.getMinFontSize() + 1; + cloud.setMinFontSize(size * 2); + Assert.assertEquals(size * 2, cloud.getMinFontSize()); + } + + // Set Words: + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords1() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setWords(null, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords2() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + words.add(null); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords3() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word w = new Word("Word"); + w.setFontData(composite.getFont().getFontData()); + w.weight = Math.random(); + words.add(w); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords4() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word w = new Word("Word"); + w.setColor(Display.getDefault().getSystemColor(SWT.COLOR_RED)); + w.weight = Math.random(); + words.add(w); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords5() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + word.angle = -180; + words.add(word); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords6() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + word.angle = 180; + words.add(word); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords7() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + word.weight = -1; + words.add(word); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords8() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + word.weight = 2; + words.add(word); + cloud.setWords(words, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetIllegalWords9() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = new Word(null); + words.add(word); + cloud.setWords(words, null); + } + + private Word getWord() { + Word w = new Word("Word"); + w.setColor(Display.getDefault().getSystemColor(SWT.COLOR_GRAY)); + w.setFontData(composite.getFont().getFontData()); + w.weight = 1; + return w; + } + + @Test + public void testSetEmptyWordList() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + int placed = cloud.setWords(words, null); + Assert.assertEquals(0, placed); + } + + @Test + public void testSetWordList() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + for (int i = 0; i < 10; i++) { + words.add(getWord()); + } + int placed = cloud.setWords(words, null); + Assert.assertEquals(10, placed); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidOpacity1() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setOpacity(-1); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidOpacity2() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setOpacity(256); + } + + // Layouter + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidLayouter() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setLayouter(null); + } + + // Zoom + + @Test + public void testZoomIn() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setWords(Arrays.asList(getWord()), null); + double zoom = cloud.getZoom(); + cloud.zoomIn(); + Assert.assertTrue(cloud.getZoom() > zoom); + } + + @Test + public void testZoomReset() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setWords(Arrays.asList(getWord()), null); + double zoom = cloud.getZoom(); + cloud.zoomReset(); + Assert.assertTrue(cloud.getZoom() > zoom); + Assert.assertEquals(cloud.getZoom(), 1.0); + } + + @Test + public void testZoomOut() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setWords(Arrays.asList(getWord()), null); + cloud.zoomReset(); + double zoom = cloud.getZoom(); + cloud.zoomOut(); + Assert.assertTrue(cloud.getZoom() < zoom); + } + + @Test + public void testZoomFit() { + TagCloud cloud = new TagCloud(composite, SWT.V_SCROLL | SWT.H_SCROLL); + cloud.setWords(Arrays.asList(getWord()), null); + cloud.zoomReset(); + double zoom = cloud.getZoom(); + cloud.zoomFit(); + Assert.assertTrue(cloud.getZoom() < zoom); + // TODO: Test if the cloud really fits the area! + } + + // Image: + + @Test + public void testGetImageData() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Assert.assertNotNull(cloud.getImageData()); + } + + // Test Selection + + @Test + public void testInitialSelection() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Set<Word> selection = cloud.getSelection(); + Assert.assertNotNull(selection); + Assert.assertTrue(selection.isEmpty()); + } + + @Test + public void testSetSelection() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + words.add(getWord()); + words.add(getWord()); + cloud.setWords(words, null); + Set<Word> sel = new HashSet<Word>(); + sel.add(words.get(0)); + cloud.setSelection(sel); + Set<Word> selection = cloud.getSelection(); + Assert.assertEquals(sel, selection); + cloud.setSelection(new HashSet<Word>()); + selection = cloud.getSelection(); + Assert.assertTrue(selection.isEmpty()); + } + + @Test + public void testSetNotExistingSelection1() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + words.add(getWord()); + words.add(getWord()); + cloud.setWords(words, null); + Set<Word> sel = new HashSet<Word>(); + sel.add(getWord()); + cloud.setSelection(sel); + Set<Word> selection = cloud.getSelection(); + Assert.assertTrue(selection.isEmpty()); + } + + @Test + public void testSetNotExistingSelection2() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Set<Word> sel = new HashSet<Word>(); + sel.add(getWord()); + cloud.setSelection(sel); + Set<Word> selection = cloud.getSelection(); + Assert.assertTrue(selection.isEmpty()); + } + + // Boost + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidBoost() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setBoost(-1); + } + + @Test + public void testSetValidBoost() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + Assert.assertEquals(0, cloud.getBoost()); + cloud.setBoost(3); + Assert.assertEquals(3, cloud.getBoost()); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetInvalidBoostFactor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setBoostFactor(0); + } + + @Test + public void testSetValidBoostFactor() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + cloud.setBoostFactor(3.3F); + Assert.assertEquals(3.3F, cloud.getBoostFactor()); + cloud.setBoostFactor(-2.2F); + Assert.assertEquals(-2.2F, cloud.getBoostFactor()); + } + + @Test + public void testLayout() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + for (int i = 0; i < 10; i++) { + words.add(getWord()); + } + // Initial position must be 0/0 + for (Word word : words) { + Assert.assertTrue(word.x == 0); + Assert.assertTrue(word.y == 0); + } + cloud.setWords(words, null); + List<Rectangle> rects = new ArrayList<Rectangle>(); + // Elements must have been placed + for (Word word : words) { + Assert.assertTrue(word.x != 0); + Assert.assertTrue(word.y != 0); + word.angle = 45f; + rects.add(new Rectangle(word.x, word.y, word.width, word.height)); + } + cloud.layoutCloud(null, false); + boolean posChanged = false; + boolean rectChanged = false; + for (int i = 0; i < words.size(); i++) { + Word w = words.get(i); + Rectangle r = rects.get(i); + if (w.x != r.x || w.y != r.y) { + posChanged = true; + } + if (w.width != r.width || w.height != r.height) { + rectChanged = true; + } + } + // Positions must have been changed + Assert.assertTrue(posChanged); + // Bounds must not have been changed + Assert.assertFalse(rectChanged); + cloud.layoutCloud(null, true); + posChanged = false; + rectChanged = false; + for (int i = 0; i < words.size(); i++) { + Word w = words.get(i); + Rectangle r = rects.get(i); + if (w.x != r.x || w.y != r.y) { + posChanged = true; + } + if (w.width != r.width || w.height != r.height) { + rectChanged = true; + } + } + // Both positions an bounds must have changed + Assert.assertTrue(posChanged); + Assert.assertTrue(rectChanged); + } + + // @Test + // public void testLayoutTooLarge() { + // TagCloud cloud = new TagCloud(composite, SWT.NONE); + // List<Word> words = new ArrayList<Word>(); + // Word w = getWord(); + // words.add(w); + // cloud.setMaxFontSize(5000); + // int placed = cloud.setWords(words, null); + // Assert.assertEquals(0, placed); + // } + + class UniversalListener implements MouseListener, MouseTrackListener, + MouseWheelListener, MouseMoveListener, SelectionListener { + + private int mouseUp; + private int mouseDown; + private int mouseDC; + private int mouseMove; + private int mouseScrolled; + private int mouseExit; + private int mouseEnter; + private int mouseHover; + private Set<Word> selection; + + public void mouseUp(MouseEvent e) { + mouseUp++; + } + + public void mouseDown(MouseEvent e) { + mouseDown++; + } + + public void mouseDoubleClick(MouseEvent e) { + mouseDC++; + } + + public void mouseMove(MouseEvent e) { + mouseMove++; + System.out.println("MOVE"); + } + + public void mouseScrolled(MouseEvent e) { + mouseScrolled++; + } + + public void mouseEnter(MouseEvent e) { + mouseEnter++; + } + + public void mouseExit(MouseEvent e) { + mouseExit++; + } + + public void mouseHover(MouseEvent e) { + mouseHover++; + } + + @SuppressWarnings("unchecked") + public void widgetSelected(SelectionEvent e) { + this.selection = (Set<Word>) e.data; + } + + public void widgetDefaultSelected(SelectionEvent e) { + + } + + } + + @Test + public void testMouseListener() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + UniversalListener ml = new UniversalListener(); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + words.add(word); + cloud.setWords(words, null); + Event e = new Event(); + cloud.addMouseListener(ml); + cloud.notifyListeners(SWT.MouseUp, e); + cloud.notifyListeners(SWT.MouseDoubleClick, e); + cloud.notifyListeners(SWT.MouseDown, e); + Assert.assertEquals(1, ml.mouseUp); + Assert.assertEquals(1, ml.mouseDC); + Assert.assertEquals(1, ml.mouseDown); + cloud.removeMouseListener(ml); + cloud.notifyListeners(SWT.MouseUp, e); + cloud.notifyListeners(SWT.MouseDoubleClick, e); + cloud.notifyListeners(SWT.MouseDown, e); + Assert.assertEquals(1, ml.mouseUp); + Assert.assertEquals(1, ml.mouseDC); + Assert.assertEquals(1, ml.mouseDown); + } + + @Test + public void testMouseMoveListener() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + words.add(word); + cloud.setWords(words, null); + Event e = new Event(); + e.x = word.x; + e.y = word.y; + UniversalListener ml = new UniversalListener(); + cloud.addMouseMoveListener(ml); + cloud.notifyListeners(SWT.MouseMove, e); + Assert.assertEquals(1, ml.mouseMove); + cloud.removeMouseMoveListener(ml); + cloud.notifyListeners(SWT.MouseMove, e); + Assert.assertEquals(1, ml.mouseMove); + } + + // @Test + // public void testMouseTrackListener() { + // // TODO: Difficult to test... involves zoom, scrollbars... + // } + + @Test + public void testMouseWheelListener() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + UniversalListener ml = new UniversalListener(); + cloud.addMouseWheelListener(ml); + cloud.notifyListeners(SWT.MouseWheel, new Event()); + Assert.assertEquals(1, ml.mouseScrolled); + cloud.removeMouseWheelListener(ml); + cloud.notifyListeners(SWT.MouseWheel, new Event()); + Assert.assertEquals(1, ml.mouseScrolled); + } + + @Test + public void testSelectionListener() { + TagCloud cloud = new TagCloud(composite, SWT.NONE); + List<Word> words = new ArrayList<Word>(); + Word word = getWord(); + words.add(word); + cloud.setWords(words, null); + UniversalListener sl = new UniversalListener(); + cloud.addSelectionListener(sl); + cloud.setSelection(new HashSet<Word>(words)); + Assert.assertEquals(1, sl.selection.size()); + cloud.setSelection(new HashSet<Word>()); + Assert.assertEquals(0, sl.selection.size()); + cloud.removeSelectionListener(sl); + cloud.setSelection(new HashSet<Word>(words)); + Assert.assertEquals(0, sl.selection.size()); + + } + +} diff --git a/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TagCloudViewerTests.java b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TagCloudViewerTests.java new file mode 100644 index 0000000..035f89f --- a/dev/null +++ b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TagCloudViewerTests.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2011 Stephan Schwiebert. 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 + * <p/> + * Contributors: Stephan Schwiebert - initial API and implementation + *******************************************************************************/ +package org.eclipse.zest.tests.cloudio; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; + +import org.eclipse.jface.viewers.BaseLabelProvider; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.zest.cloudio.TagCloud; +import org.eclipse.zest.cloudio.TagCloudViewer; +import org.eclipse.zest.cloudio.Word; +import org.eclipse.zest.cloudio.layout.DefaultLayouter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TagCloudViewerTests { + + private Display display; + private boolean createdDisplay = false; + private Composite composite; + private TagCloud cloud; + + @Before + public void setUp() throws Exception { + display = Display.getCurrent(); + if (display == null) { + display = new Display(); + createdDisplay = true; + } + composite = new Shell(display); + composite.setLayout(new FillLayout()); + cloud = new TagCloud(composite, SWT.NONE); + } + + @After + public void tearDown() throws Exception { + composite.dispose(); + if (createdDisplay) { + display.dispose(); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructor_NullCloud() { + new TagCloudViewer(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructor_DisposedCloud() { + cloud.dispose(); + new TagCloudViewer(cloud); + } + + @Test + public void testConstructor_ValidCloud() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + TagCloud cloud = viewer.getCloud(); + Assert.assertNotNull(cloud); + Assert.assertEquals(this.cloud, cloud); + Assert.assertTrue(viewer.getSelection() != null); + Assert.assertTrue(viewer.getSelection().isEmpty()); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidLabelProvider() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + viewer.setLabelProvider(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidLabelProvider2() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + viewer.setLabelProvider(new BaseLabelProvider()); + } + + @Test + public void testValidLabelProvider() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + TestLabelProvider labelProvider = new TestLabelProvider(); + viewer.setLabelProvider(labelProvider); + Assert.assertEquals(labelProvider, viewer.getLabelProvider()); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidContentProvider() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + viewer.setContentProvider(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidContentProvider2() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + viewer.setContentProvider(new IContentProvider() { + public void inputChanged(Viewer viewer, Object oldInput, + Object newInput) { + } + + public void dispose() { + } + }); + } + + private static class ListContentProvider implements ITreeContentProvider { + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public Object[] getElements(Object inputElement) { + return ((List<?>) inputElement).toArray(); + } + + public Object[] getChildren(Object parentElement) { + return null; + } + + public Object getParent(Object element) { + return null; + } + + public boolean hasChildren(Object element) { + return false; + } + + } + + @Test + public void testValidContentProvider() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + ListContentProvider provider = new ListContentProvider(); + viewer.setContentProvider(provider); + Assert.assertEquals(provider, viewer.getContentProvider()); + } + + @Test + public void testValidLabelAsignment() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + ListContentProvider provider = new ListContentProvider(); + viewer.setContentProvider(provider); + TestLabelProvider labelProvider = new TestLabelProvider(); + viewer.setLabelProvider(labelProvider); + List<String> data = new ArrayList<String>(); + data.add("Hello"); + data.add("World"); + viewer.setInput(data); + List<Word> words = viewer.getCloud().getWords(); + for (Word word : words) { + Assert.assertEquals(TestLabelProvider.COLOR, word.getColor()); + for (int i = 0; i < TestLabelProvider.FONT_DATA.length; i++) { + Assert.assertEquals(TestLabelProvider.FONT_DATA[i], + word.getFontData()[i]); + } + Assert.assertEquals(TestLabelProvider.ANGLE, word.angle); + Assert.assertEquals(TestLabelProvider.WEIGHT, word.weight); + Assert.assertTrue(word.x != 0); + Assert.assertTrue(word.y != 0); + Assert.assertTrue(word.width != 0); + Assert.assertTrue(word.height != 0); + } + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidLayouter() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + viewer.setLayouter(null); + } + + @Test + public void testValidLayouter() { + TagCloudViewer viewer = new TagCloudViewer(cloud); + DefaultLayouter layouter = new DefaultLayouter(5, 5); + viewer.setLayouter(layouter); + Assert.assertEquals(layouter, viewer.getLayouter()); + } + +} diff --git a/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TestLabelProvider.java b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TestLabelProvider.java new file mode 100644 index 0000000..6b37b1d --- a/dev/null +++ b/org.eclipse.zest.tests/src/org/eclipse/zest/tests/cloudio/TestLabelProvider.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2011 Stephan Schwiebert. 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 + * <p/> + * Contributors: Stephan Schwiebert - initial API and implementation + *******************************************************************************/ +package org.eclipse.zest.tests.cloudio; + +import org.eclipse.jface.viewers.BaseLabelProvider; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.eclipse.zest.cloudio.ICloudLabelProvider; + +public class TestLabelProvider extends BaseLabelProvider implements + ICloudLabelProvider { + + public static final double WEIGHT = 0.987D; + public static final float ANGLE = 12.34F; + public static Color COLOR = new Color(Display.getDefault(), new RGB(100, + 100, 100)); + public static FontData[] FONT_DATA = Display.getDefault().getShells()[0] + .getFont().getFontData(); + + public String getLabel(Object element) { + return element.toString(); + } + + public double getWeight(Object element) { + return WEIGHT; + } + + public Color getColor(Object element) { + return COLOR; + } + + public FontData[] getFontData(Object element) { + return FONT_DATA.clone(); + } + + public float getAngle(Object element) { + return ANGLE; + } + + public String getToolTip(Object element) { + return getLabel(element); + } + +} @@ -38,6 +38,7 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <modules> + <module>org.eclipse.zest.cloudio</module> <module>org.eclipse.zest.core</module> <module>org.eclipse.zest.jface</module> <module>org.eclipse.zest.layouts</module> |

