diff options
175 files changed, 9995 insertions, 0 deletions
diff --git a/org.eclipse.tips.core/.classpath b/org.eclipse.tips.core/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/org.eclipse.tips.core/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.tips.core/.gitignore b/org.eclipse.tips.core/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.eclipse.tips.core/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.eclipse.tips.core/.project b/org.eclipse.tips.core/.project new file mode 100644 index 000000000..85a0fc8d3 --- /dev/null +++ b/org.eclipse.tips.core/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tips.core</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.tips.core/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tips.core/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/org.eclipse.tips.core/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.eclipse.tips.core/META-INF/MANIFEST.MF b/org.eclipse.tips.core/META-INF/MANIFEST.MF new file mode 100644 index 000000000..201ad389f --- /dev/null +++ b/org.eclipse.tips.core/META-INF/MANIFEST.MF @@ -0,0 +1,11 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tip of the Day core plugin +Bundle-SymbolicName: org.eclipse.tips.core;singleton:=true +Bundle-Version: 0.1.0.qualifier +Bundle-Vendor: Eclipse Foundation +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Export-Package: org.eclipse.tips.core, + org.eclipse.tips.core.internal;x-internal:=true +Require-Bundle: org.eclipse.core.runtime;bundle-version="3.13.0" +Automatic-Module-Name: org.eclipse.tips.core diff --git a/org.eclipse.tips.core/build.properties b/org.eclipse.tips.core/build.properties new file mode 100644 index 000000000..39b31f3b5 --- /dev/null +++ b/org.eclipse.tips.core/build.properties @@ -0,0 +1,17 @@ +############################################################################### +# Copyright (c) 2018 Remain Software +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# wim.jongman@remainsoftware.com - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + images/ +src.includes = schema/ diff --git a/org.eclipse.tips.core/images/nomoretips.png b/org.eclipse.tips.core/images/nomoretips.png Binary files differnew file mode 100644 index 000000000..d77582876 --- /dev/null +++ b/org.eclipse.tips.core/images/nomoretips.png diff --git a/org.eclipse.tips.core/plugin.xml b/org.eclipse.tips.core/plugin.xml new file mode 100644 index 000000000..b29e93cdb --- /dev/null +++ b/org.eclipse.tips.core/plugin.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.4"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<plugin> + <extension-point id="tips" name="Tips" schema="schema/tips.exsd"/> +</plugin> diff --git a/org.eclipse.tips.core/pom.xml b/org.eclipse.tips.core/pom.xml new file mode 100644 index 000000000..173ccf367 --- /dev/null +++ b/org.eclipse.tips.core/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<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>eclipse.platform.ua</groupId> + <artifactId>eclipse.platform.ua</artifactId> + <version>4.8.0-SNAPSHOT</version> + </parent> + <groupId>org.eclipse.ui</groupId> + <artifactId>org.eclipse.tips.core</artifactId> + <version>0.1.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> +</project> diff --git a/org.eclipse.tips.core/schema/tips.exsd b/org.eclipse.tips.core/schema/tips.exsd new file mode 100644 index 000000000..93236edf6 --- /dev/null +++ b/org.eclipse.tips.core/schema/tips.exsd @@ -0,0 +1,455 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- Schema file written by PDE --> +<schema targetNamespace="org.eclipse.tips.core" xmlns="http://www.w3.org/2001/XMLSchema"> +<annotation> + <appinfo> + <meta.schema plugin="org.eclipse.tips.core" id="tips" name="Tips"/> + </appinfo> + <documentation> + <p> +This extension point allows bundles to hook into the eclipse tips framework. +</p> +@see Examples + </documentation> + </annotation> + + <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> + + <element name="extension"> + <annotation> + <appinfo> + <meta.element /> + </appinfo> + </annotation> + <complexType> + <choice> + <element ref="provider" minOccurs="1" maxOccurs="unbounded"/> + <element ref="category" minOccurs="1" maxOccurs="unbounded"/> + </choice> + <attribute name="point" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="id" type="string"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="name" type="string"> + <annotation> + <documentation> + + </documentation> + <appinfo> + <meta.attribute translatable="true"/> + </appinfo> + </annotation> + </attribute> + </complexType> + </element> + + <element name="provider"> + <complexType> + <sequence> + <element ref="enablement" minOccurs="0" maxOccurs="1"/> + </sequence> + <attribute name="id" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="description" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + </annotation> + </attribute> + <attribute name="class" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + <appinfo> + <meta.attribute kind="java" basedOn="org.eclipse.tips.core.TipProvider:"/> + </appinfo> + </annotation> + </attribute> + <attribute name="category" type="string" use="required"> + <annotation> + <documentation> + + </documentation> + <appinfo> + <meta.attribute kind="identifier" basedOn="org.eclipse.tips.core.tips/category/@id"/> + </appinfo> + </annotation> + </attribute> + </complexType> + </element> + + <element name="category"> + <annotation> + <documentation> + A category to group tips in the UI. + </documentation> + </annotation> + <complexType> + <attribute name="id" type="string" use="required"> + <annotation> + <documentation> + a unique name that will be used to identify this category + </documentation> + </annotation> + </attribute> + <attribute name="name" type="string" use="required"> + <annotation> + <documentation> + a translatable name that will be used in the UI for this category + </documentation> + <appinfo> + <meta.attribute translatable="true"/> + </appinfo> + </annotation> + </attribute> + <attribute name="parentCategory" type="string"> + <annotation> + <documentation> + an optional path composed of category IDs separated by '/'. This +allows the creation of a hierarchy of categories. + </documentation> + <appinfo> + <meta.attribute kind="identifier" basedOn="org.eclipse.tips.core.tips/category/@id"/> + </appinfo> + </annotation> + </attribute> + </complexType> + </element> + + + <annotation> + <appinfo> + <meta.section type="examples"/> + </appinfo> + <documentation> + <p> +This extension defines a parent category "Java"and a child category "Java9". Then the provider +is defined within category "Java9". +<pre> + <extension + point="org.eclipse.tips.ide.tips"> + <category + id="org.eclipse.tips.examples.java" + name="Java"> + </category> + <category + id="org.eclipse.tips.examples.java9" + name="Java9" + parentCategory="org.eclipse.tips.examples.java9"> + </category> + <provider + category="org.eclipse.tips.examples.java9" + class="org.eclipse.tips.examples.java.java9.Java9TipProvider" + description="Java 9 Tips" + id="org.eclipse.tips.examples.java.java9.Java9TipProvider"> + <enablement> + <with + variable="activeWorkbenchWindow.activePerspective"> + <equals + value="org.eclipse.jdt.ui.JavaPerspective"> + </equals> + </with> + </enablement> + </provider> + </extension> +</pre> +</p> + +<p> +<b>Sample implementation TipProvider</b> +</p> + +<p> + +<h1>The Implementation of a TipProvider</h1> +This is an example of a TipProvider. The framework also contains an JSon TipProvider that fetches tips inside a JSon file from a remote URL. +<b> +The example below instantiates Tips from Java. +<pre> + +/** + * Class to provide tips to the tip framework. It is the job of this provider to + * manage its tips. Examples of managing tips are: + * + * <ul> + * <li>Loading tips from the internet</li> + * <li>Serve next, previous and current tip on request</li> + * </ul> + * + * After the TipProvider is instantiated by the {@link TipManager}, the + * TipManager will insert itself by calling {@link #setManager(TipManager)}. + * Then the TipManager will asynchronous call this providers' {@link #load()} + * method. The job of the load() method is to do long work like fetching new + * tips from the internet and storing them locally. There is no defined method + * on how tips should be stored locally, implementers are free to do what is + * needed. + * + * The constructor must return fast, meaning that tips may not be fetched from + * the internet in the constructor. This should be done in the + * {@link #load(IProgressMonitor)} method. + * + * To indicate that this provider is ready to serve tips, it should call the + * {@link #setTips(List)} method which then sets its <code>ready</code> flag. + * + */ +public class Java9TipProvider extends TipProvider { + + @Override + /** + * The Id is used (for example) to manage the read state of this providers tips. + * It should be unique. + * + * @return the ID of this provider + */ + public String getID() { + return "org.eclipse.tips.examples.Java9TipProvider"; + } + + /** + * The 48x48 image may be used by the UI for low resolution displays. + * + * @return a 48x48 {@link TipImage} + */ + @Override + public TipImage getImage48() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("icons/48/java.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(getClass(), e); + } + return null; + + } + + /** + * The 64x64 image may be used by the UI for higher resolution displays. + * + * @return a 64x64 {@link TipImage} + */ + @Override + public TipImage getImage64() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("icons/64/java.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(getClass(), e); + } + return null; + + } + + /** + * Is called asynchronously during startup of the TipManager to gather new tips. + * The provider is not available to the UI unless it has called it's + * {@link #setTips(List)} method. It is therefore possible that the provider is + * not immediately visible in the tip UI but will be added later. + * + * One strategy is to do a long running fetch in this method and then store the + * tips locally. On the next run of the TipManager, the fetched tips can be + * served from the constructor (i.e. by calling {@link #setTips(List)}), making + * it immediately available. + * + * @param pMonitor + * The monitor to report back progress. + * @see TipProvider#setTips(List) + * @see TipProvider#isReady() + */ + @Override + public synchronized void load(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(this)); + tips.add(new Navigate2Tip(this)); + setTips(tips); + subMonitor.done(); + } + + /** + * @return the short description of this provider. + */ + @Override + public String getDescription() { + return "Java and Java Dev Tools Tips"; + } + + /** + * Provides the opportunity to release all held resources. + */ + @Override + public void dispose() { + } +} + +</pre> + +<h1>The Implementation of a Tip</h1> +This is an example implementation of a Tip +<pre> +/** + * This is an example Tip class. + * + */ +public class Tip1 extends Tip { + + /** + * Tips should be created fast. + * + * @param pProvider + * the associated {@link TipProvider} + */ + public Tip1(TipProvider pProvider) { + super(pProvider); + } + + /** + * A getter for a {@link Runnable} action for this tip. Clients may override or + * call {@link #setAction(Runnable)}. + * + * @return the action or null if not set by {@link Tip#setAction(Runnable)}. + * @see Tip#setAction(Runnable) + */ + @Override + public Runnable getAction() { + return new Runnable() { + @Override + public void run() { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + MessageDialog.openConfirm(null, getSubject(), "We can start an action from a Tip!"); + } + }); + } + }; + } + + /** + * Return the publish date of the tip. The {@link TipProvider} could decide to + * server newer tips first. + * + * @return the date this tip was published which may not be null. + */ + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + /** + * @return the subject which may not be null. + */ + @Override + public String getSubject() { + return "Java tip 1"; + } + + /** + * This method may both return the string representation of an URL or the + * descriptive HTML of the tip. If the html of the text is returned then an + * effort is made to also inline the image URL. If you supply an URL then + * {@link #getImage()} should return null. + * + * @return the HMTL or URL of the tip which is displayed in a browser widget. + * @see #getImage() + */ + @Override + public String getHTML() { + return "<h2>Javatip 1</h2>You see this tip because the Tip UI was opened when the java perspective " + + "was active or because you selected the Java icon below." + "<br><br>" + + "More java tips will be displayed here in the near future. For now, select one of the other providers" + + " by clicking on the icons below."; + } + + /** + * A getter for the {@link TipImage}. Subclasses may override, the default + * implementation returns null. + * + * @return a TipImage with information about the image or null if no image is + * provided. + */ + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("images/java/duke.png")).setAspectRatio(1); + } catch (IOException e) { + getProvider().getManager().log(getClass(), e); + } + return null; + } +} +</pre> + +<h1>Example of a TipImage</h1> +TipImage objects are UI agnostic representations of an Image. You may pass a URL to a TipImage or a full base64 string (e.g. "data:image/png;base64,iVBORw0KGgo.....CYII="). +<br> +One import aspect of the TipImage is it's aspect ratio. The Tip UI may use a browser to display it's UI. Therefore it can be scaled to the available space. Images look best when they use a 3:2 (1.5) ratio. +<br> +<h4>Set an image that is a square (aspect ratio = 1:1 (1)) +<pre> +TipImage img = new TipImage(bundle.getEntry("images/java/duke.png")).setAspectRatio(1) +</pre> + +<h4>Set an image that is a square (aspect ratio = 1:1 (1)) +<pre> + /** + * Sets the aspect ratio of this image. If the image is 300 wide and 600 high + * then the aspect ratio is 300/600 = 0,5 (1:2). If your image is 1200 wide and + * 250 high then the aspect ratio (1200/250) = 4,8. With the supplied values the + * best dimensions for the image can be calculated give the available space in + * the UI. + * <p> + * In case you pass true for <code>pSetAsMax</code> then the image can not be + * up-scaled beyond the specified size. So if your image is 200x200 and you want + * a maximum up-scale of 2 then pass 400x400 to this method to maintain the + * aspect ratio but allow the image to be resized to maximum it's double size. + * <p> + * The recommended aspect ratio is around 3:2 (1.5) to be comfortably displayed + * in the Tip UI. + ** + TipImage img = new TipImage("data:image/png;base64,3ff4..eFW"); + img.setAspectRatio(800, 400, true); // Image can not be scaled up higer than 800:400 +</pre> + +</p> + </documentation> + </annotation> + + + + <annotation> + <appinfo> + <meta.section type="copyright"/> + </appinfo> + <documentation> + Copyright (c) 2017 Remain Software + + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Wim Jongman <wim.jongman@remainsoftware.com> - Initial implementation + </documentation> + </annotation> + +</schema> diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/IHtmlTip.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/IHtmlTip.java new file mode 100644 index 000000000..b6373111a --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/IHtmlTip.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + + +/** + * Decoration of {@link Tip} that enables HTML content. + * + */ +public interface IHtmlTip { + + /** + * Returns the HTML of the tip to be rendered in the tip UI, together or without + * the {@link #getImage()}. + * + * @return the HMTL of the tip + * @see #getImage() + */ + public String getHTML(); + + /** + * Returns the {@link TipImage}. + * + * @return a TipImage with information about the image or <code>null</code> if the this information cannot be created + * @see #getHTML() + */ + public TipImage getImage(); + +} diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/ITipManager.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/ITipManager.java new file mode 100644 index 000000000..a722914b5 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/ITipManager.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import org.eclipse.core.runtime.IStatus; + +/** + * The model maintained by the TipManager. + * + */ +public interface ITipManager { + + /** + * Indicates whether already read tips must be served or not. + * + * @return true or false + * @see TipManager#setServeReadTips(boolean) + */ + public boolean mustServeReadTips(); + + /** + * Consults TipManager to determine the Tip's read status. + * + * @param tip + * the tip to query for its read status + * @return true if the tip is read, false otherwise. + */ + public abstract boolean isRead(Tip tip); + + /** + * Instructs the TipManager to mark this tip as read. + * + * @param tip + * the tip to set as read. + * @return this + */ + public abstract ITipManager setAsRead(Tip tip); + + /** + * Central place of logging for the Tip Framework. + * + * @param status + * the {@link IStatus} which may not be null + * @return this + */ + public ITipManager log(IStatus status); + + /** + * Binds the passed provider to this manager. After registration, ITipManager + * implementations should asynchronously call the + * {@link TipProvider#loadNewTips(org.eclipse.core.runtime.IProgressMonitor)} + * method. + * + * @param provider + * the {@link TipProvider} to register which may not be null. + * @return this + */ + public ITipManager register(TipProvider provider); + + /** + * Returns the disposed stated. + * + * @return true if this manager is disposed, false otherwise. + */ + public boolean isDisposed(); +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/IUrlTip.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/IUrlTip.java new file mode 100644 index 000000000..01ec04a59 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/IUrlTip.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import java.net.URL; + +/** + * Decoration of {@link Tip} that enables URL content. + * + */ +public interface IUrlTip { + + /** + * Return an URL with the primary goal to be rendered by the tip manager. + * Implementations of Tip may also use the URL to aid the rendering (e.g. by + * providing other data than HTML, e.g. a text file). + * + * @return the URL to the (remote) content + * + */ + public URL getURL(); +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/Tip.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/Tip.java new file mode 100644 index 000000000..8d5cf112c --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/Tip.java @@ -0,0 +1,109 @@ +/**************************************************************************** + * Copyright (c) 2017, 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation + *****************************************************************************/ +package org.eclipse.tips.core; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * This is the base Tip class of the UI agnostic Tip framework. You might want + * to check specializations of this class that may make your life easier. + * + */ +public abstract class Tip { + + private String providerId; + + private final List<TipAction> fActions = new ArrayList<>(); + + /** + * Constructor for a Tip. For the best user experience, Tips should be created + * really fast. + * + */ + public Tip(String providerId) { + this.providerId = providerId; + } + + /** + * For the sanity of the Framework, Tips should be created really fast. + * + * @param pProvider + * the associated {@link TipProvider} + * @param actions + * the list of actions which may not be null + */ + public Tip(List<TipAction> actions) { + fActions.addAll(actions); + } + + /** + * A getter for a list of {@link TipAction}s for this tip. Clients may override + * or provide the actions through the constructor. + * + * @return the list of actions, never null but could be empty. + */ + public List<TipAction> getActions() { + return fActions; + } + + /** + * Return the publish date of the tip. The UI could decide to server newer tips + * first. + * + * @return the date this tip was published which may not be null. + */ + public abstract Date getCreationDate(); + + + /** + * @return the subject which may not be null. + */ + public abstract String getSubject(); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getCreationDate() == null) ? 0 : getCreationDate().hashCode()); + result = prime * result + ((providerId == null) ? 0 : providerId.hashCode()); + result = prime * result + ((getSubject() == null) ? 0 : getSubject().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Tip other = (Tip) obj; + if (getCreationDate() == null) { + if (other.getCreationDate() != null) + return false; + } else if (!getCreationDate().equals(other.getCreationDate())) + return false; + if (providerId == null) { + if (other.providerId != null) + return false; + } else if (!providerId.equals(other.providerId)) + return false; + if (getSubject() == null) { + if (other.getSubject() != null) + return false; + } else if (!getSubject().equals(other.getSubject())) + return false; + return true; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipAction.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipAction.java new file mode 100644 index 000000000..e73a2ac72 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipAction.java @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation + *****************************************************************************/ +package org.eclipse.tips.core; + +/** + * Provides an action to be executed by a Tip. + * + */ +public class TipAction { + + private final String fText; + private final TipImage fTipImage; + private final Runnable fRunner; + private final String fTooltip; + + /** + * Creates a new TipAction. Tip actions can be executed in the tip UI when the + * associated Tip is displayed. + * + * @param text + * a very short description to be used on buttons and menus. + * @param tooltip + * a longer description to be shown as tool tip when possible. + * @param runner + * the actual code to run + * @param image + * the image to be shown when possible. + * + */ + public TipAction(String text, String tooltip, Runnable runner, TipImage image) { + fText = text; + fTooltip = tooltip; + fRunner = runner; + fTipImage = image; + } + + /** + * The short description of the action to be shown as button text or menu entry + * when possible. + * + * @return the text + */ + public String getText() { + return fText; + } + + /** + * A longer description to be shown as tool tip when possible. + * + * @return the tool tip. + */ + public String getTooltip() { + return fTooltip; + } + + /** + * The icon of the image wrapped in a TipImage. + * + * @return the icon + */ + public TipImage getTipImage() { + return fTipImage; + } + + /** + * The actual code to run when this action is executed. + * + * @return the runner. + */ + public Runnable getRunner() { + return fRunner; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java new file mode 100644 index 000000000..18a12e791 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipImage.java @@ -0,0 +1,298 @@ +/**************************************************************************** + * Copyright (c) 2017, 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation + *****************************************************************************/ +package org.eclipse.tips.core; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Base64; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tips.core.internal.ImageUtil; + +/** + * Provides more information about the image to be used in the tip. The image + * aspect ratio must be around 3:2 to be comfortably displayed in the Tip UI. + * + */ +public class TipImage { + + private static final double THREE_TO_TWO = 1.5; + + /** + * Value to indicate that the height or width are to be determined by the Tip + * framework. + */ + public static final int UNDEFINED = -1; + + private String fExtension = null; + private int fMaxWidth = UNDEFINED; + private int fMaxHeight = UNDEFINED; + final private URL fURL; + private double fAspectRatio = THREE_TO_TWO; + + final private String fBase64Image; + + private static final int _4KB = 4096; + + /** + * Creates a new TipImage with the specified URL which gets read into a base 64 + * string. + * + * @param url + * the image URL which may not be null + * @throws IOException + * in case the stream of the passed URL could not be opened or read. + * + */ + public TipImage(URL url) throws IOException { + Assert.isNotNull(url); + fURL = url; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] chunk = new byte[_4KB]; + int bytesRead; + InputStream stream = url.openStream(); + while ((bytesRead = stream.read(chunk)) > 0) { + outputStream.write(chunk, 0, bytesRead); + } + fBase64Image = "data:image/" // + + getExtension() // + + ";base64," // + + Base64.getEncoder().encodeToString(outputStream.toByteArray()); + } + + /** + * @return true if the URL constructor was used and not the base64 constructor. + */ + public boolean isURLSet() { + return fURL != null; + } + + /** + * Creates a new {@link TipImage} with the specified base64 string which must be + * a valid RFC-2397 string thats begins with + * <code>"data:image/<subtype>;base64"</code> where <code>subtype</code> + * must be a valid image type (pmg, bmp, gif, etc..). + * + * @param base64Image + * the non-null base64 encoded image according to RFC-2397. + * + * @throws RuntimeException + * if the string is not valid + * @see TipImage + * @see <a href="https://tools.ietf.org/search/rfc2397">RFC-2397 + * (https://tools.ietf.org/search/rfc2397)</a> + * + */ + public TipImage(String base64Image) { + Assert.isNotNull(base64Image); + fURL = null; + if (base64Image.matches("^data:image\\/.*?;base64,.*$")) { + fBase64Image = base64Image; + int from = base64Image.indexOf("/") + 1; + int to = base64Image.indexOf(";"); + setExtension(base64Image.substring(from, to).trim()); + setExtension(base64Image.substring(from, to).trim()); + } else { + int length = base64Image.length(); + throw new RuntimeException("Wrong base64 data " + base64Image.substring(0, length < 50 ? length : 50)); + } + } + + /** + * Sets the maximum height that this image can display. For example, if you have + * a 32x32 image the framework will blow it up to a larger size which will not + * work for the image and you might want to pass 64 to indicate that the image + * cannot be resized passed 64 pixels. If the height is not set or set to + * {@link #UNDEFINED}, then it is automatically resized based on aspect ratio + * and maximum width. + * + * @param maxHeight + * the maximum height for this image or {@link #UNDEFINED} + * @return this + * @see #setAspectRatio(double) + * @see #setAspectRatio(int, int, boolean) + * @see #setMaxWidth(int) + */ + public TipImage setMaxHeight(int maxHeight) { + fMaxHeight = maxHeight; + return this; + } + + /** + * Sets the maximum width that this image can display. For example, if you have + * a 32x32 image the framework will blow it up to a larger size which will not + * work for the image and you might want to pass 64 to indicate that the image + * cannot be resized passed 64 pixels. If the width is not set or set to + * {@link #UNDEFINED}, it is automatically resized based on aspect ratio and + * maximum height. + * + * @param maxWidth + * the maximum width for this image or {@link #UNDEFINED} + * @return this + * @see #setAspectRatio(double) + * @see #setAspectRatio(int, int, boolean) + * @see #setMaxHeight(int) + */ + public TipImage setMaxWidth(int maxWidth) { + fMaxWidth = maxWidth; + return this; + } + + /** + * Sets the aspect ratio of this image. If the image is 300 wide and 600 high + * then the aspect ratio is 300/600 = 0,5 (1:2). If your image is 1200 wide and + * 250 high then the aspect ratio (1200/250) = 4,8. With the supplied values the + * best dimensions for the image can be calculated give the available space in + * the UI. + * <p> + * In case you pass true for <code>pSetAsMax</code> then the image can not be + * up-scaled beyond the specified size. So if your image is 200x200 and you want + * a maximum up-scale of 2 then pass 400x400 to this method to maintain the + * aspect ratio but allow the image to be resized to maximum it's double size. + * <p> + * The recommended aspect ratio is around 3:2 (1.5) to be comfortably displayed + * in the Tip UI. + * + * @param width + * the width of the image, must be greater than 0 + * @param height + * the height of the image, must be greater than 0 + * @param setAsMax + * true to set the passed width and height as the maximum width and + * height for the image + * @return this + * @see #setAspectRatio(double) + * @see #getIMGAttributes(int, int) + * @see #setMaxHeight(int) + * @see #setMaxWidth(int) + */ + public TipImage setAspectRatio(int width, int height, boolean setAsMax) { + Assert.isTrue(width > 0); + Assert.isTrue(height > 0); + fAspectRatio = (double) width / (double) height; + if (setAsMax) { + setMaxHeight(height); + setMaxWidth(width); + } + return this; + } + + /** + * Sets the aspect ratio of your image which is defined by width divided by + * height. + * <p> + * The recommended aspect ratio is around 3:2 (1.5) to be comfortably displayed + * in the Tip UI. + * + * + * @param aspectRatio + * the aspect ration + * @return this + * @see #setAspectRatio(int, int, boolean) + * @see #getIMGAttributes(int, int) + */ + public TipImage setAspectRatio(double aspectRatio) { + fAspectRatio = aspectRatio; + return this; + } + + /** + * Changes the default value "null" to the passed value which commonly is "png", + * "gif" and such. + * + * @param extension + * the extension of this file + * @return this + * @see #getExtension() + */ + public TipImage setExtension(String extension) { + fExtension = extension; + return this; + } + + /** + * Returns the base64 encoded image string according to RFC-2397 or null. The + * recommended aspect ratio is around 3:2. + * + * @return the base64 encoded image string according to RFC-2397 or null + */ + public String getBase64Image() { + return fBase64Image; + } + + /** + * Returns the width and height attributes of the HTML IMG tag. + * + * <pre> + * <img src="smiley.gif" height="42" width="42"> + * </pre> + * + * The available space in the UI is passed and with it the best size of the + * image will be calculated based on the aspect ratio of this image. + * + * Clients may override if they can provide better information. + * + * @param widthHint + * the available width which must be greater than 0 + * @param heightHint + * the available height which must be greater than 0 + * @return the attributes in the HTML img tag + * @see TipImage#setAspectRatio(double) + * @see TipImage#setAspectRatio(int, int, boolean) + * @see TipImage#setMaxHeight(int) + * @see TipImage#setMaxWidth(int) + */ + public String getIMGAttributes(int widthHint, int heightHint) { + + int myWidthHint = (fMaxWidth == UNDEFINED) ? widthHint : Math.min(widthHint, fMaxWidth); + int myHeightHint = (fMaxHeight == UNDEFINED) ? heightHint : Math.min(heightHint, fMaxHeight); + + int width = ImageUtil.getWidth(fAspectRatio, myWidthHint, myHeightHint); + int height = ImageUtil.getHeight(fAspectRatio, myWidthHint, myHeightHint); + + String result = ""; + if (fMaxWidth == UNDEFINED) { + result += " width=\"" + width + "\""; + } else { + result += " width=\"" + Math.min(fMaxWidth, width) + "\""; + } + + if (fMaxHeight == UNDEFINED) { + result += " height=\"" + height + "\""; + } else { + result += " height=\"" + Math.min(fMaxHeight, height) + "\""; + } + return result; + } + + /** + * Returns the image extension for use in the IMG tag for the data attribute + * (<code>data:image/???</code>). If the extension is not set in this object, + * then the URL is examined to find the extension. If that can not be determined + * then "png" is returned. + * + * @return the extension + */ + private String getExtension() { + if (fExtension != null) { + return fExtension; + } + String[] split = fURL.getPath().split("\\."); + if (split.length > 1) { + fExtension = split[split.length - 1]; + } else { + fExtension = "png"; + } + return fExtension; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipManager.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipManager.java new file mode 100644 index 000000000..2101f160c --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipManager.java @@ -0,0 +1,260 @@ +/**************************************************************************** + * Copyright (c) 2017, 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation + *****************************************************************************/ +package org.eclipse.tips.core; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.eclipse.tips.core.internal.LogUtil; + +/** + * An abstract implementation of ITipManager with additional control API. While + * the rest of the framework must work with ITipManager, this class provides API + * to open the dialog and do low level housekeeping that is of no concern to + * external participants (Tip and TipProvider). + * + */ +public abstract class TipManager implements ITipManager { + + private Map<String, TipProvider> fProviders = new HashMap<>(); + private Map<Integer, List<String>> fProviderPrio = new TreeMap<>(); + protected boolean fOpen; + private boolean fServeReadTips = false; + private TipProviderListenerManager fListenerManager = new TipProviderListenerManager(); + private boolean fIsDiposed; + + /** + * Instantiates a new TipManager. + */ + public TipManager() { + } + + /** + * Gets the provider with the specified ID. + * + * @param providerID + * the id of the provider to fetch + * @return the provider with the specified ID or null if no such provider + * exists. + * @see TipProvider#getID() + */ + public TipProvider getProvider(String providerID) { + checkDisposed(); + return fProviders.get(providerID); + } + + /** + * Binds the passed provider to this manager. Implementations should override, + * call super and the asynchronously call the + * {@link TipProvider#loadNewTips(org.eclipse.core.runtime.IProgressMonitor)} + * method. + * + * @param provider + * the {@link TipProvider} to register. + * + * @return this + */ + @Override + public ITipManager register(TipProvider provider) { + checkDisposed(); + log(LogUtil.info("Registering provider: " + provider.getID() + " : " + provider.getDescription())); + provider.setManager(this); + addToMaps(provider, new Integer(getPriority(provider))); + provider.getListenerManager().addProviderListener( + myProvider -> getListenerManager().notifyListeners(TipProviderListener.EVENT_READY, myProvider)); + return this; + } + + private void checkDisposed() { + if (isDisposed()) { + throw new RuntimeException("This TipManager is disposed."); + } + + } + + /** + * Calculates the priority that this provider has in the Tips framework. The + * {@link TipProvider#getExpression()} was purposed to aid in the calculation of + * the priority. + * + * @param provider + * the provider + * @return the priority, lower is higher, never negative. + */ + public abstract int getPriority(TipProvider provider); + + private synchronized void addToMaps(TipProvider pProvider, Integer pPriorityHint) { + removeFromMaps(pProvider); + addToProviderMaps(pProvider, pPriorityHint); + addToPriorityMap(pProvider, pPriorityHint); + } + + private void addToPriorityMap(TipProvider provider, Integer priorityHint) { + if (!fProviderPrio.get(priorityHint).contains(provider.getID())) { + if (!fProviderPrio.get(priorityHint).contains(provider.getID())) { + fProviderPrio.get(priorityHint).add(provider.getID()); + } + } + } + + private void addToProviderMaps(TipProvider provider, Integer priorityHint) { + fProviders.put(provider.getID(), provider); + if (fProviderPrio.get(priorityHint) == null) { + fProviderPrio.put(priorityHint, new ArrayList<>()); + } + } + + private void removeFromMaps(TipProvider provider) { + if (fProviders.containsKey(provider.getID())) { + for (Map.Entry<Integer, List<String>> entry : fProviderPrio.entrySet()) { + entry.getValue().remove(provider.getID()); + } + fProviders.remove(provider.getID()); + } + } + + /** + * The returned list contains providers ready to serve tips and is guaranteed to + * be in a prioritised order according the implementation of this manager. + * + * @return the prioritised list of ready providers with tips in an immutable + * list. + */ + public List<TipProvider> getProviders() { + checkDisposed(); + if (fProviders == null) { + return Collections.emptyList(); + } + ArrayList<TipProvider> result = new ArrayList<>(); + for (Map.Entry<Integer, List<String>> entry : fProviderPrio.entrySet()) { + for (String id : entry.getValue()) { + if (fProviders.get(id).isReady()) { + result.add(fProviders.get(id)); + } + } + } + return Collections.unmodifiableList(result); + } + + /** + * Determines if the Tips framework must run at startup. The default + * implementation returns true, subclasses should probably override this. + * + * @return true if the Tips framework should run at startup. + * @see TipManager#setRunAtStartup(boolean) + */ + public boolean isRunAtStartup() { + checkDisposed(); + return true; + } + + /** + * Determines if the Tips framework must run at startup. + * + * @param shouldRun + * true if the tips should be displayed at startup, false otherwise. + * + * @return this + * + * @see #isRunAtStartup() + */ + public abstract TipManager setRunAtStartup(boolean shouldRun); + + /** + * Opens the Tip of the Day dialog. + * + * @param startUp + * When called from a startup situation, true must be passed for + * <code>pStartup</code>. If in a manual starting situation, false + * must be passed. This enables the manager to decide to skip opening + * the dialog at startup (e.g., no new tip items). + * + * @return this + * + * @see #isOpen() + */ + public abstract TipManager open(boolean startUp); + + /** + * The default implementation disposes of this manager and all the TipProviders + * when the dialog is disposed. Subclasses may override but must call super. + */ + public void dispose() { + checkDisposed(); + try { + for (TipProvider provider : fProviders.values()) { + try { + provider.dispose(); + } catch (Exception e) { + log(LogUtil.error(e)); + } + } + } finally { + fProviders.clear(); + fProviderPrio.clear(); + fIsDiposed = true; + } + } + + /** + * @return returns true if the tips are currently being displayed in some way. + */ + public boolean isOpen() { + checkDisposed(); + return fOpen; + } + + /** + * Indicates whether read tips must be served or not. Subclasses could override, + * to save the state somewhere, but must call super. + * + * @param serveRead + * true of read tips may be served by the {@link TipProvider}s + * @return this + * @see TipManager#mustServeReadTips() + */ + public TipManager setServeReadTips(boolean serveRead) { + checkDisposed(); + fServeReadTips = serveRead; + return this; + } + + /** + * Indicates whether already read tips must be served or not. + * + * @return true or false + * @see #setServeReadTips(boolean) + */ + @Override + public boolean mustServeReadTips() { + checkDisposed(); + return fServeReadTips; + } + + /** + * Gets the listener manager so that interested parties can subscribe to the + * events of this provider. + * + * @return the listener manager, never null. + */ + public TipProviderListenerManager getListenerManager() { + return fListenerManager; + } + + @Override + public boolean isDisposed() { + return fIsDiposed; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProvider.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProvider.java new file mode 100644 index 000000000..fde1da7b3 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProvider.java @@ -0,0 +1,332 @@ +/**************************************************************************** + * Copyright (c) 2017, 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation + *****************************************************************************/ +package org.eclipse.tips.core; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.tips.core.internal.FinalTip; + +/** + * Class to provide tips to the tip framework. It is the job of this provider to + * manage its tips. Examples of managing tips are: + * + * <ul> + * <li>Loading tips from the internet</li> + * <li>Serve next, previous and current tip on request</li> + * </ul> + * + * After the TipProvider is instantiated by the {@link ITipManager}, the + * TipManager will insert itself by calling {@link #setManager(ITipManager)}. + * Then the TipManager will asynchronous call this providers' + * {@link #loadNewTips(IProgressMonitor)} method. The job of the load() method + * is to do long work like fetching new tips from the internet and storing them + * locally. There is no defined method on how tips should be stored locally, + * implementers are free to do what is needed. + * + * The constructor must return fast, meaning that tips may not be fetched from + * the Internet in the constructor. This should be done in the + * {@link #loadNewTips(IProgressMonitor)} method. + * + * To indicate that this provider is ready to serve tips, it should call the + * {@link #setTips(List)} method which then sets its <code>ready</code> flag. + * + */ +public abstract class TipProvider { + + private ITipManager fTipManager; + private int fTipIndex; + protected List<Tip> fTips = new ArrayList<>(); + private Tip fCurrentTip; + private boolean fReady; + private TipProviderListenerManager fListenerManager = new TipProviderListenerManager(); + private Tip fFinalTip = new FinalTip(getID()); + private String fExpression; + + /** + * The zero argument constructor must be able to instantiate the TipProvider. + * This method may also be used to quickly set the available tips by calling the + * {@link #setTips(List)} method. The constructor may not be used to load tips + * from the internet. Use the {@link #loadNewTips(IProgressMonitor)} method for + * this purpose. + * + * @see #loadNewTips(IProgressMonitor) + * @see #setTips(List) + */ + public TipProvider() { + } + + /** + * Provides the opportunity to release all held resources. + */ + public abstract void dispose(); + + /** + * @return the short description of this provider. + */ + public abstract String getDescription(); + + /** + * @return the ID of this provider + */ + public abstract String getID(); + + /** + * The image used by the UI for low resolution + * + * @return a 48x48 {@link TipImage} + */ + public abstract TipImage getImage(); + + /** + * Get a list of tips. The default implementation returns tips based on the + * following conditions: <br> + * <dl> + * <dt><code>pFilter</code> is false</dt> + * <dd>Return all read and unread tips.</dd> + * <dt><code>pFilter</code> is true</dt> + * <dd>Return read and unread tips if the tipManager may serve unread tips, + * otherwise return only unread tips.</dd> + * </dl> + * <p> + * Subclasses may override (calling super(false) to fetch the list) if they want + * to serve or sort the list of tips in a different way. + * + * @param filter + * false or true, see description above. + * @return an unmodifiable list of tips. + */ + public synchronized List<Tip> getTips(boolean filter) { + if (filter) { + return Collections.unmodifiableList(fTips // + .stream() // + .filter(tip -> getManager().mustServeReadTips() || !getManager().isRead(tip)) // + .sorted(Comparator.comparing(Tip::getCreationDate).reversed()) // + .collect(Collectors.toList())); + } + return Collections.unmodifiableList(fTips); + } + + /** + * @return the {@link Tip} that was last returned by {@link #getNextTip()} or + * {@link #getPreviousTip()} + */ + public synchronized Tip getCurrentTip() { + if (fCurrentTip == null) { + return getNextTip(); + } + return fCurrentTip; + } + + /** + * The next {@link Tip} is returned based on the read status of the Tip and the + * fact if already read tips must be served or not which is known by the + * {@link ITipManager}: ({@link ITipManager#mustServeReadTips()}). + * + * @return the next {@link Tip} + * @see #getPreviousTip() + * @see #getCurrentTip() + */ + public synchronized Tip getNextTip() { + boolean unreadOnly = !getManager().mustServeReadTips(); + List<Tip> list = getTips(unreadOnly); + if (list.isEmpty()) { + return setCurrentTip(fFinalTip); + } + if (!unreadOnly && fCurrentTip != null) { + fTipIndex++; + } else if (fCurrentTip != null && getManager().isRead(fCurrentTip)) { + fTipIndex++; + } + if (fTipIndex >= list.size()) { + fTipIndex = 0; + } + return setCurrentTip(list.get(fTipIndex)); + } + + /** + * @return the previous {@link Tip} + * @see #getNextTip() + * @see #getCurrentTip() + */ + public Tip getPreviousTip() { + List<Tip> list = getTips(!getManager().mustServeReadTips()); + if (list.isEmpty()) { + return setCurrentTip(fFinalTip); + } + fTipIndex--; + if (fTipIndex < 0) { + fTipIndex = list.size() - 1; + } + return setCurrentTip(list.get(fTipIndex)); + } + + /** + * @return the {@link ITipManager} of this provider, never null. + */ + public synchronized ITipManager getManager() { + return fTipManager; + } + + /** + * @return true if the provider is ready to deliver tips + */ + public final boolean isReady() { + return fReady; + } + + /** + * Is called asynchronously during startup of the TipManager to gather new tips. + * + * The provider is not available to the UI unless it has called it's + * {@link #setTips(List)} method. It is therefore possible that the provider is + * not immediately visible in the tip UI but will be added later. + * <p> + * If you run out of tips and you feel that you should load more tips on your + * own then you can also asynchronously call this method. A good place would be + * to override {@link #getTips(boolean)}, check if the supply of tips is + * sufficient and then call this method asynchronously. + * <p> + * One strategy is to do a long running fetch in this method and then store the + * tips locally. On the next run of the TipManager, the fetched tips can be + * served from the constructor (i.e. by calling {@link #setTips(List)}), making + * them available immediately + * + * @param monitor + * The monitor to report back progress. + * @return the status in case you want to report problems. + * @see TipProvider#setTips(List) + * @see TipProvider#isReady() + */ + public abstract IStatus loadNewTips(IProgressMonitor monitor); + + private synchronized Tip setCurrentTip(Tip pTip) { + fCurrentTip = pTip; + return fCurrentTip; + } + + /** + * Sets the TipManager. You should probably not call this method directly. This + * method is normally called after the provider is instantiated by the + * {@link ITipManager}. If you create the provider yourself you should register + * the provider with {@link ITipManager#register(TipProvider)} which in turn + * will call this method. Subclasses may override but must not forget to call + * super in order to save the {@link ITipManager}. + * + * @param tipManager + * the {@link ITipManager} + * @return this + */ + public synchronized TipProvider setManager(ITipManager tipManager) { + fTipManager = tipManager; + return this; + } + + /** + * Sets the tips for this provider, replacing the current set of tips, and sets + * the <code>ready</code> flag to true. This method is typically called from the + * constructor of the {@link TipProvider} but may also be called from the + * asynchronous {@link #loadNewTips(IProgressMonitor)} method. + * + * @param tips + * a list of {@link Tip} objects + * @return this + * @see #addTips(List) + * @see #isReady() + * @see #loadNewTips(IProgressMonitor) + */ + public TipProvider setTips(List<Tip> tips) { + if(getManager().isDisposed()) { + return this; + } + doSetTips(tips, true); + fReady = true; + fListenerManager.notifyListeners(TipProviderListener.EVENT_READY, this); + return this; + } + + /** + * Adds the passed tips to the set of tips this provider already has sets the + * <code>ready</code> flag to true. This method is typically called from the + * constructor of the {@link TipProvider} but may also be called from the + * asynchronous {@link #loadNewTips(IProgressMonitor)} method. + * + * @param tips + * a list of {@link Tip} objects + * @return this + * @see #setTips(List) + * @see #isReady() + * @see #loadNewTips(IProgressMonitor) + */ + public TipProvider addTips(List<Tip> tips) { + doSetTips(tips, false); + fReady = true; + fListenerManager.notifyListeners(TipProviderListener.EVENT_READY, this); + return this; + } + + private synchronized void doSetTips(List<Tip> tips, boolean replace) { + if (replace) { + fTips.clear(); + } + fTips.addAll(tips); + } + + /** + * Gets the listener manager so that interested parties can subscribe to the + * events of this provider. + * + * @return the {@link TipProviderListenerManager} + */ + public TipProviderListenerManager getListenerManager() { + return fListenerManager; + } + + /** + * Returns an expression that is used by the {@link ITipManager} to determine + * the priority of this provider. The expression can be used to advice the + * TipManager when the tips of this provider deserve priority. The Eclipse IDE + * TipManager uses the core expression from the o.e.core.runtime bundle. + * Example: The expression + * + * <pre> + * <with + * variable="activeWorkbenchWindow.activePerspective"> + * <equals value="org.eclipse.jdt.ui.JavaPerspective"></equals> + * </with> + * </pre> + * + * will give the provider priority when the java perspective is active in the + * IDE + * + * @return the expression which can be empty or null. + */ + public String getExpression() { + return fExpression; + } + + /** + * Sets the expression to determine the priority of the provider. + * + * @param expression + * the expression, may be null. + * + * @see #getExpression() + */ + public void setExpression(String expression) { + fExpression = expression; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProviderListener.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProviderListener.java new file mode 100644 index 000000000..f9d4b59d3 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProviderListener.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +/** + * Provides notifications on TipProvider events. + * + */ +@FunctionalInterface +public interface TipProviderListener { + + /** + * Event ready. The TipProvider is ready to serve tips. + */ + public static final int EVENT_READY = 1; + + /** + * When the subject is ready to serve tips (e.g. fetched new tips from + * somewhere) it will The provider is ready to serve tips. The default + * implementation does nothing, subclasses may override. + * + * @param provider + * the provider. + */ + public void providerReady(TipProvider provider); +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProviderListenerManager.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProviderListenerManager.java new file mode 100644 index 000000000..985cb0ecd --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/TipProviderListenerManager.java @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (c) 2017, 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wim Jongman <wim.jongman@remainsoftware.com> - initial API and implementation + *****************************************************************************/ +package org.eclipse.tips.core; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class to manage provider listeners. + */ +public class TipProviderListenerManager { + + protected List<TipProviderListener> fListeners = new ArrayList<>(); + + /** + * Notifies all listeners that an event occurred. + * + * @param event + * the event + * @param provider + * the provider + */ + public void notifyListeners(int event, TipProvider provider) { + synchronized (fListeners) { + for (TipProviderListener tipProviderListener : fListeners) { + switch (event) { + case TipProviderListener.EVENT_READY: + tipProviderListener.providerReady(provider); + break; + } + } + } + } + + /** + * Adds a listener to the list of listeners. + * + * @param pProviderListener + * the listener to be notified + * @return this + */ + public TipProviderListenerManager addProviderListener(TipProviderListener pProviderListener) { + fListeners.remove(pProviderListener); + fListeners.add(pProviderListener); + return this; + } + + /** + * Removes a listener from the list of listeners. + * + * @param pProviderListener + * the listener to remove + * @return this + */ + public TipProviderListenerManager removeProviderListener(TipProviderListener pProviderListener) { + fListeners.remove(pProviderListener); + return this; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/FinalTip.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/FinalTip.java new file mode 100644 index 000000000..fbc8b8c26 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/FinalTip.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core.internal; + +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * Special generic tip that tells the user that there are no more tips. + * + */ +public class FinalTip extends Tip implements IHtmlTip { + + /** + * Constructor. + */ + public FinalTip(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + Calendar instance = Calendar.getInstance(); + return instance.getTime(); + } + + @Override + public String getSubject() { + return "No more tips"; + } + + @Override + public String getHTML() { + return "<h1>There are no more tips</h1>" // + + "This provider has no more new tips. You can toggle the " // + + "<b>Unread</b> checkbox below or select another provider."; + } + + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("images/nomoretips.png")).setAspectRatio(417, 640, false); + } catch (IOException e) { +// getManager().log(LogUtil.error(getClass(), e)); + } + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/ImageUtil.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/ImageUtil.java new file mode 100644 index 000000000..0a338de6c --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/ImageUtil.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core.internal; + +/** + * Image helper class. + * + */ +public class ImageUtil { + + /** + * Calculate a height that will fit in the proposed rectangle given the passed + * aspect ratio. + * + * @param aspectRatio + * the aspect ration, e.g. 1.5 for a 3/2 ratio (width/height). + * @param widthHint + * the available width in the viewport + * @param heightHint + * the available height in the viewport + * @return the maximum height that will fit in the passed rectangle. + */ + public static int getHeight(double aspectRatio, int widthHint, int heightHint) { + return (int) Math.min(heightHint, widthHint / aspectRatio); + } + + /** + * Calculate a width that will fit in the proposed rectangle given the passed + * aspect ratio. + * + * @param aspectRatio + * the aspect ration, e.g. 1.5 for a 3/2 ratio (width/height). + * @param widthHint + * the available width in the viewport + * @param heightHint + * the available height in the viewport + * @return the maximum width that will fit in the rectangle. + */ + public static int getWidth(double aspectRatio, int widthHint, int heightHint) { + return (int) Math.min(widthHint, heightHint * aspectRatio); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/LogUtil.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/LogUtil.java new file mode 100644 index 000000000..976f4e03e --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/LogUtil.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core.internal; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.osgi.framework.FrameworkUtil; + +public class LogUtil { + + public static IStatus getStatus(int severity, String bundleId, String message, Throwable throwable) { + return new Status(severity, bundleId, message, throwable); + } + + public static IStatus error(Throwable throwable) { + return getStatus(IStatus.ERROR, "org.eclipse.tips.core", throwable.getMessage(), throwable); + } + + public static IStatus warn(Throwable throwable) { + return getStatus(IStatus.WARNING, "org.eclipse.tips.core", throwable.getMessage(), throwable); + } + + public static IStatus info(Throwable throwable) { + return getStatus(IStatus.INFO, "org.eclipse.tips.core", throwable.getMessage(), throwable); + } + + public static IStatus error(Class<?> clazz, Throwable throwable) { + return getStatus(IStatus.ERROR, getBundleId(clazz), throwable.getMessage(), throwable); + } + + public static IStatus warn(Class<?> clazz, Throwable throwable) { + return getStatus(IStatus.WARNING, getBundleId(clazz), throwable.getMessage(), throwable); + } + + public static IStatus info(Class<?> clazz, Throwable throwable) { + return getStatus(IStatus.INFO, getBundleId(clazz), throwable.getMessage(), throwable); + } + + public static IStatus info(Class<?> clazz, String message) { + return getStatus(IStatus.INFO, getBundleId(clazz), message, null); + } + + public static IStatus warn(Class<?> clazz, String pessage) { + return getStatus(IStatus.WARNING, getBundleId(clazz), pessage, null); + } + + public static IStatus error(Class<?> clazz, String message) { + return getStatus(IStatus.ERROR, getBundleId(clazz), message, null); + } + + private static String getBundleId(Class<?> clazz) { + if (FrameworkUtil.getBundle(clazz) != null) { + return FrameworkUtil.getBundle(clazz).getSymbolicName(); + } + return "osgi.not.running"; + } + + public static IStatus info(String message) { + return getStatus(IStatus.INFO, "org.eclipse.tips.core", message, null); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/package-info.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/package-info.java new file mode 100644 index 000000000..c790f96d4 --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/internal/package-info.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Tip Framework API internal classes. + */ +package org.eclipse.tips.core.internal;
\ No newline at end of file diff --git a/org.eclipse.tips.core/src/org/eclipse/tips/core/package-info.java b/org.eclipse.tips.core/src/org/eclipse/tips/core/package-info.java new file mode 100644 index 000000000..f63aef9af --- /dev/null +++ b/org.eclipse.tips.core/src/org/eclipse/tips/core/package-info.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Tip Framework core API. A UI agnostic API for the Tip of the Day. Known + * implementation is in package org.eclipse.tips.ui. If you run in the Eclipse + * IDE you may use the tips extension point to register a new + * {@link org.eclipse.tips.core.TipProvider}.If you want to run the Tip + * framework outside of the IDE (e.g. in an RCP application) then you should + * also implement your own {@link org.eclipse.tips.core.TipManager} and start + * that with some action or at startup of your application. + */ +package org.eclipse.tips.core;
\ No newline at end of file diff --git a/org.eclipse.tips.examples/.classpath b/org.eclipse.tips.examples/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/org.eclipse.tips.examples/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.tips.examples/.gitignore b/org.eclipse.tips.examples/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.eclipse.tips.examples/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.eclipse.tips.examples/.project b/org.eclipse.tips.examples/.project new file mode 100644 index 000000000..13d6a0d84 --- /dev/null +++ b/org.eclipse.tips.examples/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tips.examples</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.tips.examples/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tips.examples/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/org.eclipse.tips.examples/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.eclipse.tips.examples/META-INF/MANIFEST.MF b/org.eclipse.tips.examples/META-INF/MANIFEST.MF new file mode 100644 index 000000000..7dd6c1b4d --- /dev/null +++ b/org.eclipse.tips.examples/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tip of the Day Examples +Bundle-SymbolicName: org.eclipse.tips.examples;singleton:=true +Bundle-Version: 0.1.0.qualifier +Bundle-Vendor: Eclipse +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.core.runtime;bundle-version="3.13.0", + org.eclipse.tips.core;bundle-version="0.1.0", + org.eclipse.tips.json;bundle-version="0.1.0", + org.eclipse.swt, + org.eclipse.jface, + org.eclipse.tips.ui;bundle-version="0.1.0" +Eclipse-BundleShape: dir +Import-Package: org.osgi.framework;version="1.8.0" +Automatic-Module-Name: org.eclipse.tips.examples diff --git a/org.eclipse.tips.examples/build.properties b/org.eclipse.tips.examples/build.properties new file mode 100644 index 000000000..5e55821c1 --- /dev/null +++ b/org.eclipse.tips.examples/build.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2018 Remain Software +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# wim.jongman@remainsoftware.com - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + icons/,\ + matrixrain/,\ + images/ diff --git a/org.eclipse.tips.examples/icons/48/c++.png b/org.eclipse.tips.examples/icons/48/c++.png Binary files differnew file mode 100644 index 000000000..11e205e6d --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/c++.png diff --git a/org.eclipse.tips.examples/icons/48/ecf.png b/org.eclipse.tips.examples/icons/48/ecf.png Binary files differnew file mode 100644 index 000000000..af873b30f --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/ecf.png diff --git a/org.eclipse.tips.examples/icons/48/eclipse.png b/org.eclipse.tips.examples/icons/48/eclipse.png Binary files differnew file mode 100644 index 000000000..276f40be6 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/eclipse.png diff --git a/org.eclipse.tips.examples/icons/48/java.png b/org.eclipse.tips.examples/icons/48/java.png Binary files differnew file mode 100644 index 000000000..7129f6d73 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/java.png diff --git a/org.eclipse.tips.examples/icons/48/key.png b/org.eclipse.tips.examples/icons/48/key.png Binary files differnew file mode 100644 index 000000000..920d543e5 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/key.png diff --git a/org.eclipse.tips.examples/icons/48/nebula.png b/org.eclipse.tips.examples/icons/48/nebula.png Binary files differnew file mode 100644 index 000000000..80d5057cf --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/nebula.png diff --git a/org.eclipse.tips.examples/icons/48/pin.png b/org.eclipse.tips.examples/icons/48/pin.png Binary files differnew file mode 100644 index 000000000..a7bfc70e1 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/pin.png diff --git a/org.eclipse.tips.examples/icons/48/plugin.png b/org.eclipse.tips.examples/icons/48/plugin.png Binary files differnew file mode 100644 index 000000000..ef644a0a8 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/plugin.png diff --git a/org.eclipse.tips.examples/icons/48/pydev.png b/org.eclipse.tips.examples/icons/48/pydev.png Binary files differnew file mode 100644 index 000000000..72639f65c --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/pydev.png diff --git a/org.eclipse.tips.examples/icons/48/swt.png b/org.eclipse.tips.examples/icons/48/swt.png Binary files differnew file mode 100644 index 000000000..cc6a5ea3a --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/swt.png diff --git a/org.eclipse.tips.examples/icons/48/tips.png b/org.eclipse.tips.examples/icons/48/tips.png Binary files differnew file mode 100644 index 000000000..cd19de252 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/tips.png diff --git a/org.eclipse.tips.examples/icons/48/twitter.png b/org.eclipse.tips.examples/icons/48/twitter.png Binary files differnew file mode 100644 index 000000000..5f17261f9 --- /dev/null +++ b/org.eclipse.tips.examples/icons/48/twitter.png diff --git a/org.eclipse.tips.examples/icons/64/c++.png b/org.eclipse.tips.examples/icons/64/c++.png Binary files differnew file mode 100644 index 000000000..a948ccbef --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/c++.png diff --git a/org.eclipse.tips.examples/icons/64/ecf.png b/org.eclipse.tips.examples/icons/64/ecf.png Binary files differnew file mode 100644 index 000000000..57e09478a --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/ecf.png diff --git a/org.eclipse.tips.examples/icons/64/eclipse.png b/org.eclipse.tips.examples/icons/64/eclipse.png Binary files differnew file mode 100644 index 000000000..01aa23b91 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/eclipse.png diff --git a/org.eclipse.tips.examples/icons/64/java.png b/org.eclipse.tips.examples/icons/64/java.png Binary files differnew file mode 100644 index 000000000..36cbf25c2 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/java.png diff --git a/org.eclipse.tips.examples/icons/64/key.png b/org.eclipse.tips.examples/icons/64/key.png Binary files differnew file mode 100644 index 000000000..cc1694c12 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/key.png diff --git a/org.eclipse.tips.examples/icons/64/nebula.png b/org.eclipse.tips.examples/icons/64/nebula.png Binary files differnew file mode 100644 index 000000000..674fe6cb4 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/nebula.png diff --git a/org.eclipse.tips.examples/icons/64/pin.png b/org.eclipse.tips.examples/icons/64/pin.png Binary files differnew file mode 100644 index 000000000..c065db4cf --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/pin.png diff --git a/org.eclipse.tips.examples/icons/64/plugin.png b/org.eclipse.tips.examples/icons/64/plugin.png Binary files differnew file mode 100644 index 000000000..a75ab0593 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/plugin.png diff --git a/org.eclipse.tips.examples/icons/64/pydev.png b/org.eclipse.tips.examples/icons/64/pydev.png Binary files differnew file mode 100644 index 000000000..ece92aa5d --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/pydev.png diff --git a/org.eclipse.tips.examples/icons/64/swt.png b/org.eclipse.tips.examples/icons/64/swt.png Binary files differnew file mode 100644 index 000000000..6acbcb124 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/swt.png diff --git a/org.eclipse.tips.examples/icons/64/tips.png b/org.eclipse.tips.examples/icons/64/tips.png Binary files differnew file mode 100644 index 000000000..32fb73b60 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/tips.png diff --git a/org.eclipse.tips.examples/icons/64/twitter.png b/org.eclipse.tips.examples/icons/64/twitter.png Binary files differnew file mode 100644 index 000000000..dc874f378 --- /dev/null +++ b/org.eclipse.tips.examples/icons/64/twitter.png diff --git a/org.eclipse.tips.examples/icons/asterisk_yellow.png b/org.eclipse.tips.examples/icons/asterisk_yellow.png Binary files differnew file mode 100644 index 000000000..bab7cc9bc --- /dev/null +++ b/org.eclipse.tips.examples/icons/asterisk_yellow.png diff --git a/org.eclipse.tips.examples/icons/bug_link.png b/org.eclipse.tips.examples/icons/bug_link.png Binary files differnew file mode 100644 index 000000000..30e25abac --- /dev/null +++ b/org.eclipse.tips.examples/icons/bug_link.png diff --git a/org.eclipse.tips.examples/icons/clock.png b/org.eclipse.tips.examples/icons/clock.png Binary files differnew file mode 100644 index 000000000..e2672c206 --- /dev/null +++ b/org.eclipse.tips.examples/icons/clock.png diff --git a/org.eclipse.tips.examples/icons/cut.png b/org.eclipse.tips.examples/icons/cut.png Binary files differnew file mode 100644 index 000000000..f215d6f6b --- /dev/null +++ b/org.eclipse.tips.examples/icons/cut.png diff --git a/org.eclipse.tips.examples/icons/lightbulb.png b/org.eclipse.tips.examples/icons/lightbulb.png Binary files differnew file mode 100644 index 000000000..d22fde8ba --- /dev/null +++ b/org.eclipse.tips.examples/icons/lightbulb.png diff --git a/org.eclipse.tips.examples/images/eclipsetips/tip1.gif b/org.eclipse.tips.examples/images/eclipsetips/tip1.gif Binary files differnew file mode 100644 index 000000000..14a62bdd9 --- /dev/null +++ b/org.eclipse.tips.examples/images/eclipsetips/tip1.gif diff --git a/org.eclipse.tips.examples/images/eclipsetips/tip2.png b/org.eclipse.tips.examples/images/eclipsetips/tip2.png Binary files differnew file mode 100644 index 000000000..2e2fab32e --- /dev/null +++ b/org.eclipse.tips.examples/images/eclipsetips/tip2.png diff --git a/org.eclipse.tips.examples/images/eclipsetips/tip3.png b/org.eclipse.tips.examples/images/eclipsetips/tip3.png Binary files differnew file mode 100644 index 000000000..adbe9bdb3 --- /dev/null +++ b/org.eclipse.tips.examples/images/eclipsetips/tip3.png diff --git a/org.eclipse.tips.examples/images/java/duke.png b/org.eclipse.tips.examples/images/java/duke.png Binary files differnew file mode 100644 index 000000000..4a4e303d1 --- /dev/null +++ b/org.eclipse.tips.examples/images/java/duke.png diff --git a/org.eclipse.tips.examples/images/tips/navigate1.png b/org.eclipse.tips.examples/images/tips/navigate1.png Binary files differnew file mode 100644 index 000000000..4f4fc3a2d --- /dev/null +++ b/org.eclipse.tips.examples/images/tips/navigate1.png diff --git a/org.eclipse.tips.examples/images/tips/navigate2.png b/org.eclipse.tips.examples/images/tips/navigate2.png Binary files differnew file mode 100644 index 000000000..dcac33c9b --- /dev/null +++ b/org.eclipse.tips.examples/images/tips/navigate2.png diff --git a/org.eclipse.tips.examples/images/tips/starttip.gif b/org.eclipse.tips.examples/images/tips/starttip.gif Binary files differnew file mode 100644 index 000000000..045318617 --- /dev/null +++ b/org.eclipse.tips.examples/images/tips/starttip.gif diff --git a/org.eclipse.tips.examples/images/tips/tip2.gif b/org.eclipse.tips.examples/images/tips/tip2.gif Binary files differnew file mode 100644 index 000000000..d3850990f --- /dev/null +++ b/org.eclipse.tips.examples/images/tips/tip2.gif diff --git a/org.eclipse.tips.examples/images/tips/tipsfw.png b/org.eclipse.tips.examples/images/tips/tipsfw.png Binary files differnew file mode 100644 index 000000000..8eeb6009f --- /dev/null +++ b/org.eclipse.tips.examples/images/tips/tipsfw.png diff --git a/org.eclipse.tips.examples/matrixrain/index.html b/org.eclipse.tips.examples/matrixrain/index.html new file mode 100644 index 000000000..f3d53bd7c --- /dev/null +++ b/org.eclipse.tips.examples/matrixrain/index.html @@ -0,0 +1,26 @@ +<html> +<head> + <meta charset="UTF-8"> + <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.min.js"></script> + <!-- uncomment lines below to include extra p5 libraries --> + <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/addons/p5.dom.min.js"></script> + <!--<script language="javascript" src="libraries/p5.sound.js"></script>--> + <script type="text/javascript" src="matrixrain.js"></script> + <script type="text/javascript" src="particle.js"></script> + <!-- this line removes any default padding and style. you might only need one of these values set. --> + <style type="text/css"> + body { + margin: 0px; + } + + canvas { + display: block; + } + + </style> +</head> + +<body> + +</body> +</html>
\ No newline at end of file diff --git a/org.eclipse.tips.examples/matrixrain/matrixrain.js b/org.eclipse.tips.examples/matrixrain/matrixrain.js new file mode 100644 index 000000000..a03ca729c --- /dev/null +++ b/org.eclipse.tips.examples/matrixrain/matrixrain.js @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +// Copyright 2017 Wim Jongman +// var nice = [200, 200, 0.02, 0.002, 10, 2000, 4]; +// var nice = [7280, 4320 , 0.02, 0.002, 10, 2000, 4]; +var nice = [ 1440, 900, 0.02, 0.002, 20, 50, 4 ]; +// var nice = [600, 600, 0.02, 0.002, 50, 1000, 3]; +var myX; +var myY; +var inc; +var incTime; +var scl; +var parts; +var magnitude; + +var fr; +var time = 0; +var iteration = 0; +var counter = 0; + +var particles = []; + +var flowField; + +var lanes = new Array(); + +var pg; + +function setup() { + + myX = nice[0]; + myY = nice[1]; + inc = nice[2]; + incTime = nice[3]; + scl = nice[4]; + parts = nice[5]; + magnitude = nice[6]; + + createCanvas(window.innerWidth, window.innerHeight); + document.body.scrollTop = 0; // <-- pull the page back up to the top + document.body.style.overflow = 'hidden'; // <-- relevant addition + + pixelDensity(1); + generateParticles(); +} + +function draw() { + background(0, 120); + updateParticles(); +} + +function generateParticles() { + for (var i = 0; i < parts; i++) { + particles[i] = new Particle(); + } +} + +function updateParticles() { + textSize(12); + textStyle(BOLD); + for (var i = 0; i < parts; i++) { + p = particles[i]; + if (p.isActive()) { + p.applyForce(); + p.update(); + show(p); + } + } +} + +function show(particle) { + doShow(particle, 0); + for (var i = 1; i < particle.fTrail.length; i++) { + doShow(particle, i, particle.fTrail.length); + } +} + +function doShow(particle, pos, len) { + if (pos == 0) { + fill(200, 255, 200, 255); + } else if ((len - pos) < 4) { + fill(255 - (len - pos) * 50, 255, 255 - (len - pos) * 50, + 200 - (len - pos) * 20); + } else { + fill(0, 255, 0, particle.getOpacity(pos)); + } + text(particle.getChar(pos), particle.getX(pos), particle.getY(pos)); +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/matrixrain/particle.js b/org.eclipse.tips.examples/matrixrain/particle.js new file mode 100644 index 000000000..d67254fc1 --- /dev/null +++ b/org.eclipse.tips.examples/matrixrain/particle.js @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +// Copyright 2017 Wim Jongman +function Particle() { + + this.init = function(first) { + this.fTrail = new Array(); + this.fChar = new Array(); + this.fOpac = new Array(); + this.scalar = 10; + this.fForce = createVector(0, this.scalar); + if (first) { + this.active = Math.floor(random(50)); + } + this.alive = 0; + this.laneNumber = this.getFreeLane(); + lanes[this.laneNumber] = true; + this.theY = 0; + if (first) { + this.theY = Math.floor(random(height / 2)); + } + this.pos = createVector(this.laneNumber * this.scalar, this.theY); + this.vel = createVector(0, 0); + this.acc = createVector(0, 0); + this.prv = createVector(0, 0); + this.speed = Math.floor(random(10) + 1); + this.char = this.getRandomChar(); + this.fTrail[this.fTrail.length] = this.pos; + this.fChar[this.fChar.length] = this.char; + this.fOpac[this.fOpac.length] = 255; + } + + this.getRandomChar = function() { + if (Math.round(random()) == 1) { + return char(Math.floor(12458 + random(74))); + } + return char(Math.floor(47 + random(43))); + } + + /** + * Become active after a while. + */ + this.isActive = function() { + if (this.active <= 0) { + return true; + } + this.active--; + return false; + } + + this.getFreeLane = function() { + var numberOfLanes = Math.floor(width / this.scalar); + var result = Math.floor(random(numberOfLanes)); + while (lanes[result] == true) { + result = Math.floor(random(numberOfLanes)); + } + return result; + } + + this.update = function() { + // console.log(this.alive, this.fTrail.length, this.pos.y); + if (this.pos.y > height + && (this.alive > 0 && (this.alive + 5) >= this.fTrail.length)) { + lanes[this.laneNumber] = false; + this.init(false); + } + + else if (this.pos.y <= height + 20) { + var copy = this.pos.copy(); + this.fTrail[this.fTrail.length] = copy; + this.fChar[this.fChar.length] = this.char; + this.fOpac[this.fOpac.length] = 200; + this.vel.add(this.acc); + this.pos.add(this.vel); + this.vel.limit(this.speed); + this.acc.mult(0); + this.char = this.getRandomChar(); + } + } + + this.getOpacity = function(pos) { + var count = this.fOpac[pos]; + this.fOpac[pos] -= this.speed; + if (this.fTrail[pos].y > height) { + this.fOpac[pos] = 0;// (this.speed * 100); + } + if (count > 0 && this.fOpac[pos] <= 0) { + this.alive += 2; + } + return this.fOpac[pos]; + } + + this.getX = function(pos) { + return this.fTrail[pos].x; + } + + this.getY = function(pos) { + return this.fTrail[pos].y; + } + + this.getChar = function(pos) { + if (Math.floor(random(10)) == 5) { + this.fChar[pos] = this.getRandomChar(); + } + if (pos == 0) { + return this.getRandomChar(); + } + return this.fChar[pos]; + } + + this.applyForce = function() { + this.acc.add(this.fForce); + } + + this.init(true); +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/plugin.xml b/org.eclipse.tips.examples/plugin.xml new file mode 100644 index 000000000..6c13e2410 --- /dev/null +++ b/org.eclipse.tips.examples/plugin.xml @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.4"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<plugin> + <extension + point="org.eclipse.tips.core.tips"> + <category + id="org.eclipse.tips.examples.tips.tipsfw" + name="Tips Framework"> + </category> + <provider + category="org.eclipse.tips.examples.tips.tipsfw" + class="org.eclipse.tips.examples.tipsframework.TipsTipProvider" + description="Eclipse Tips" + id="org.eclipse.tips.examples.tips.tipsframework.TipsTipProvider"> + </provider> + <provider + category="org.eclipse.tips.examples.tips.tipsfw" + class="org.eclipse.tips.examples.json.JsonTipProviderPhoton" + description="Eclipse Photon New and Noteworthy" + id="org.eclipse.tips.examples.tips.tipsframework.photonnn"> + </provider> + </extension> + <extension + point="org.eclipse.tips.core.tips"> + <category + id="org.eclipse.tips.examples.tips.java" + name="Java"> + </category> + <category + id="org.eclipse.tips.examples.tips.java9" + name="Java9" + parentCategory="org.eclipse.tips.examples.tips.java9"> + </category> + <provider + category="org.eclipse.tips.examples.tips.java9" + class="org.eclipse.tips.examples.java.java9.Java9TipProvider" + description="Java 9 Tips" + id="org.eclipse.tips.examples.tips.java.java9.Java9TipProvider"> + <enablement> + <with + variable="activeWorkbenchWindow.activePerspective"> + <equals + value="org.eclipse.jdt.ui.JavaPerspective"> + </equals> + </with> + </enablement> + </provider> + </extension> + <extension + point="org.eclipse.tips.core.tips"> + <category + id="org.eclipse.tips.examples.tips.eclipsetips" + name="Eclipse IDE Tips"> + </category> + <provider + category="org.eclipse.tips.examples.tips.eclipsetips" + class="org.eclipse.tips.examples.eclipsetips.EclipseTipsProvider" + description="Eclipse Tips" + id="org.eclipse.tips.examples.tips.eclipsetips.EclipseTipsProvider"> + </provider> + </extension> + <extension + point="org.eclipse.tips.core.tips"> + <category + id="org.eclipse.tips.examples.tips.eclipsetips" + name="Eclipse IDE Tips"> + </category> + <provider + category="org.eclipse.tips.examples.tips.eclipsetips" + class="org.eclipse.tips.examples.test.TestProvider" + description="Test Provider" + id="org.eclipse.tips.examples.tips.test.TestProvider"> + </provider> + </extension> + <extension + point="org.eclipse.tips.core.tips"> + <provider + category="org.eclipse.tips.examples.tips.eclipsetips" + class="org.eclipse.tips.examples.swttip.SwtTipsProvider" + description="SWT Tips Provider" + id="org.eclipse.tips.examples.swttip.SWTTipsProvider"> + </provider> + </extension> + +</plugin> diff --git a/org.eclipse.tips.examples/pom.xml b/org.eclipse.tips.examples/pom.xml new file mode 100644 index 000000000..f18f8274c --- /dev/null +++ b/org.eclipse.tips.examples/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<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>eclipse.platform.ua</groupId> + <artifactId>eclipse.platform.ua</artifactId> + <version>4.8.0-SNAPSHOT</version> + </parent> + <groupId>org.eclipse.ui</groupId> + <artifactId>org.eclipse.tips.examples</artifactId> + <version>0.1.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> +</project> diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/DateUtil.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/DateUtil.java new file mode 100644 index 000000000..2d5226e7a --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/DateUtil.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Date utilities. + * + */ +public class DateUtil { + + /** + * Convenience method that creates a date from a dd/mm/yy string. + * + * @param pYYMMDD + * the date in a dd/mm/yy format, e.g. "01/01/2017" + * @return the date + * @throws RuntimeException + * if the date is not correct + */ + public static Date getDateFromYYMMDD(String pYYMMDD) { + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); + try { + return sdf.parse(pYYMMDD); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/EclipseTipsProvider.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/EclipseTipsProvider.java new file mode 100644 index 000000000..c9fdbbacc --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/EclipseTipsProvider.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.eclipsetips; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.eclipse.tips.examples.tips.MediaWikiTip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class EclipseTipsProvider extends org.eclipse.tips.core.TipProvider { + + public int fCurrentTip; + + private Tip createTip1() { + return new org.eclipse.tips.examples.tips.TwitterTip(getID(), "https://twitter.com/EclipseJavaIDE/status/919915440041840641", DateUtil.getDateFromYYMMDD("08/12/017"), + "Twitter Tip"); + } + + private Tip createTip2() { + return new org.eclipse.tips.examples.tips.MediaWikiTip(getID(), "https://wiki.eclipse.org/Tip_of_the_Day/Eclipse_Tips/Show_In_System_Explorer", + DateUtil.getDateFromYYMMDD("08/01/2017"), "Show in Systems Explorer"); + } + + private MediaWikiTip createTip3() { + return new org.eclipse.tips.examples.tips.MediaWikiTip(getID(), + "https://wiki.eclipse.org/Tip_of_the_Day/Eclipse_Tips/Now_where_was_I", + DateUtil.getDateFromYYMMDD("08/01/2017"), "Where was I?"); + } + + private Tip createTip4() { + return new org.eclipse.tips.examples.tips.MediaWikiTip(getID(), + "https://twitter.com/EclipseJavaIDE/status/949238007051235328", + DateUtil.getDateFromYYMMDD("08/01/2017"), "Extract class"); + } + + private MediaWikiTip createTip5() { + return new org.eclipse.tips.examples.tips.MediaWikiTip(getID(), + "https://twitter.com/EclipseJavaIDE/status/919915440041840641", + DateUtil.getDateFromYYMMDD("08/01/2017"), "Junit Jupiter Test"); + } + + @Override + public String getDescription() { + return "General Eclipse IDE Tips"; + } + + @Override + public String getID() { + return getClass().getName(); + } + + private TipImage fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/eclipse.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Tip2(getID())); + tips.add(new Tip3(getID())); + tips.add(createTip1()); + tips.add(createTip2()); + tips.add(createTip3()); + tips.add(createTip4()); + tips.add(createTip5()); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip1.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip1.java new file mode 100644 index 000000000..86903b0de --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip1.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.eclipsetips; + +import java.io.IOException; +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class Tip1 extends Tip implements IHtmlTip { + + public Tip1(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + @Override + public String getSubject() { + return "This is SwtTipImpl"; + } + + @Override + public String getHTML() { + return "<h1>Iterate with Iterator</h1>" // + + "Workbench editors keep a navigation history." // + + " If you open a second editor while you're editing," + + " you can press <b>Navigate > Backward (Alt+Left Arrow," + + " or the Left arrow icon back arrow icon on the" + + " workbench toolbar)</b> to go back to the last editor." + + " This makes working with several open editors a whole lot easier." + "<br/><br/>"; + } + + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("images/eclipsetips/tip1.gif")).setAspectRatio(560.0 / 266.0); + } catch (IOException e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + return null; + + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip2.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip2.java new file mode 100644 index 000000000..b6bd14322 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip2.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.eclipsetips; + +import java.io.IOException; +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class Tip2 extends Tip implements IHtmlTip { + + + public Tip2(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + @Override + public String getSubject() { + return "Quick Access"; + } + + @Override + public String getHTML() { + return "<h1>Quick access</h1>You can quickly find all manner of" + + " user interface elements with the <b>Quick Access</b>" + + " search bar at the top of the workbench window. Click" + + " in the field or use the <b>Ctrl+3</b> binding to switch" + + " focus to it. Matching elements include (but are not limited to)" + + " open editors, available perspectives, views, preferences, wizards," + + " and commands. Simply start typing the name of the item you wish to" + + " invoke and we will attempt to find something in the Workbench that" + + " matches the provided string. "; + } + + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("images/eclipsetips/tip2.png")); + } catch (IOException e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + return null; + + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip3.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip3.java new file mode 100644 index 000000000..c67d4403f --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/Tip3.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.eclipsetips; + +import java.io.IOException; +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class Tip3 extends Tip implements IHtmlTip { + + + public Tip3(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + @Override + public String getSubject() { + return "Auto Save"; + } + + @Override + public String getHTML() { + return "<h1>Automatic Save of dirty editors</h1>You can configure the automatic save of dirty editors in Eclipse via the <b>General > Editors > Autosave</b> preference page which allows you to enable/disable the autosave and change the interval of autosave."; + } + + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("images/eclipsetips/tip3.png")).setAspectRatio(658.0 / 581.0); + } catch (IOException e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + return null; + + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/TwitterTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/TwitterTip.java new file mode 100644 index 000000000..afe11e766 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/eclipsetips/TwitterTip.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.eclipsetips; + +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.examples.DateUtil; + +public class TwitterTip extends Tip implements IHtmlTip { + + public TwitterTip(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + @Override + public String getSubject() { + return "CTRL+1 Quick Assists"; + } + + @Override + public String getHTML() { + return "<html><head><style>" + + "</style></head><body><div><blockquote class=\"twitter-tweet\" data-lang=\"en\"><p lang=\"en\" dir=\"ltr\">The 'Extract class...' refactoring (from Alt+Shift+T) extracts a group of fields into a separate class and replaces all occurrences to fit the new structure. See example. <a href=\"https://twitter.com/hashtag/EclipseTips?src=hash&ref_src=twsrc%5Etfw\">#EclipseTips</a> <a href=\"https://t.co/tEI7ic7C1g\">pic.twitter.com/tEI7ic7C1g</a></p>— Eclipse Java IDE (@EclipseJavaIDE) <a href=\"https://twitter.com/EclipseJavaIDE/status/949238007051235328?ref_src=twsrc%5Etfw\">January 5, 2018</a></blockquote>" + + "<script src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script></div></body></html>"; + } + + @Override + public TipImage getImage() { + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/java/java9/Java9TipProvider.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/java/java9/Java9TipProvider.java new file mode 100644 index 000000000..16e532921 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/java/java9/Java9TipProvider.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.java.java9; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * + + * + */ +public class Java9TipProvider extends TipProvider { + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("icons/48/java.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + return null; + + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public String getDescription() { + return "Java and Java Dev Tools Tips"; + } + + @Override + public void dispose() { + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/java/java9/Tip1.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/java/java9/Tip1.java new file mode 100644 index 000000000..5d9045522 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/java/java9/Tip1.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.java.java9; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipAction; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * This is an example Tip class. + * + */ +public class Tip1 extends Tip implements IHtmlTip { + + /** + * Tips should be created fast. + * + * @param pProvider + * the associated {@link TipProvider} + */ + public Tip1(String providerId) { + super(providerId); + } + + @Override + public List<TipAction> getActions() { + Runnable runnable = () -> Display.getDefault() + .syncExec(() -> MessageDialog.openConfirm(null, getSubject(), "We can start an action from a Tip!")); + + ArrayList<TipAction> actions = new ArrayList<>(); + actions.add(new TipAction("Tip1 Action", "Just a silly action", runnable, null)); + return actions; + } + + /** + * Return the publish date of the tip. The {@link TipProvider} could decide to + * server newer tips first. + * + * @return the date this tip was published which may not be null. + */ + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + /** + * @return the subject which may not be null. + */ + @Override + public String getSubject() { + return "Java tip 1"; + } + + /** + * This method may both return the string representation of an URL or the + * descriptive HTML of the tip. If the html of the text is returned then an + * effort is made to also inline the image URL. If you supply an URL then + * {@link #getImage()} should return null. + * + * @return the HMTL or URL of the tip which is displayed in a browser widget. + * @see #getImage() + */ + @Override + public String getHTML() { + return "<h2>Javatip 1</h2>You see this tip because the Tip UI was opened when the java perspective " + + "was active or because you selected the Java icon below." + "<br><br>" + + "More java tips will be displayed here in the near future. For now, select one of the other providers" + + " by clicking on the icons below."; + } + + /** + * A getter for the {@link TipImage}. Subclasses may override, the default + * implementation returns null. + * + * @return a TipImage with information about the image or null if no image is + * provided. + */ + @Override + public TipImage getImage() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry("images/java/duke.png")).setAspectRatio(1); + } catch (IOException e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/json/JsonTipProviderPhoton.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/json/JsonTipProviderPhoton.java new file mode 100644 index 000000000..d77193c1a --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/json/JsonTipProviderPhoton.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.json; + +import java.net.MalformedURLException; + +import org.eclipse.tips.json.JsonTipProvider; + +public class JsonTipProviderPhoton extends JsonTipProvider { + + public JsonTipProviderPhoton() throws MalformedURLException { + setJsonUrl("https://raw.githubusercontent.com/wimjongman/jsontips/master/photon/m3tips.json"); + } + + @Override + public String getID() { + return getClass().getName(); + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/swttip/SwtTipImpl.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/swttip/SwtTipImpl.java new file mode 100644 index 000000000..faeb61c3b --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/swttip/SwtTipImpl.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.swttip; + +import java.util.Date; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.examples.DateUtil; +import org.eclipse.tips.ui.ISwtTip; + +public class SwtTipImpl extends Tip implements ISwtTip { + + private final class Beeper extends SelectionAdapter { + @Override + public void widgetSelected(SelectionEvent e) { + e.widget.getDisplay().beep(); + if (((Button) e.widget).getText().contains("2")) { + try { + Thread.sleep(600); + } catch (InterruptedException e1) { + } + e.widget.getDisplay().beep(); + } + } + } + + private String fSubject; + + public SwtTipImpl(String providerId, int number) { + super(providerId); + fSubject = "This is a tip " + number; + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("10/01/2018"); + } + + @Override + public String getSubject() { + return fSubject; + } + + @Override + public void createControl(Composite pParent) { + pParent.setLayout(new GridLayout(2, false)); + Group group = new Group(pParent, SWT.NONE); + GridDataFactory.fillDefaults().span(2, SWT.DEFAULT).grab(true, true).applyTo(group); + group.setLayout(new FillLayout()); + group.setText(fSubject); + Text text = new Text(group, SWT.MULTI | SWT.WRAP); + text.setText(fSubject + System.lineSeparator() + System.lineSeparator() + + "There are thousands of these tips. Just press next tip and you will see."); + Button button1 = new Button(pParent, SWT.PUSH); + button1.setText("Beep once"); + button1.addSelectionListener(new Beeper()); + GridDataFactory.fillDefaults().applyTo(button1); + Button button2 = new Button(pParent, SWT.PUSH); + button2.setText("Beep 2 times"); + button2.addSelectionListener(new Beeper()); + GridDataFactory.fillDefaults().applyTo(button2); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/swttip/SwtTipsProvider.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/swttip/SwtTipsProvider.java new file mode 100644 index 000000000..5424fdd68 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/swttip/SwtTipsProvider.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.swttip; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class SwtTipsProvider extends TipProvider { + + private TipImage fImage64, fImage48; + private int fCounter; + private boolean fFetching; + + @Override + public String getDescription() { + return "Never ending list of SWT Tips"; + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public synchronized List<Tip> getTips(boolean pFilter) { + List<Tip> tips = super.getTips(pFilter); + if (tips.size() <= 1) { + Job job = new Job(getDescription() + " is getting more tips.") { + + @Override + protected IStatus run(IProgressMonitor pMonitor) { + return loadNewTips(pMonitor); + } + }; + job.setUser(true); + job.schedule(); + } + return tips; + } + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/swt.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + if (fFetching) { + return Status.CANCEL_STATUS; + } + try { + subMonitor.beginTask("Loading Tips for " + getDescription(), -1); + List<Tip> tips = new ArrayList<>(); + tips.add(new SwtTipImpl(getID(),1)); + tips.add(new SwtTipImpl(getID(),2)); + tips.add(new SwtTipImpl(getID(),3)); + tips.add(new SwtTipImpl(getID(),4)); + tips.add(new SwtTipImpl(getID(),5)); + addTips(tips); + return Status.OK_STATUS; + } finally { + fFetching = false; + subMonitor.done(); + } + } + + @Override + public void dispose() { + } + + public int getCounter() { + return ++fCounter; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider.java new file mode 100644 index 000000000..6036ace4d --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/c++.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + + if (System.getProperty("tips.test") == null) { + return Status.OK_STATUS; + } + + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + getManager().register(new TestProvider1()); + getManager().register(new TestProvider2()); + getManager().register(new TestProvider3()); + getManager().register(new TestProvider4()); + getManager().register(new TestProvider5()); + getManager().register(new TestProvider6()); + getManager().register(new TestProvider7()); + int sleep = new Random().nextInt(10000) + 1000; + while (sleep > 0) { + try { + Thread.sleep(500); + sleep -= 500; + subMonitor.subTask("Sleeping " + sleep); + } catch (InterruptedException e) { + } + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider1.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider1.java new file mode 100644 index 000000000..5e900cd70 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider1.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider1 extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/key.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + int sleep = new Random().nextInt(10000) + 1000; + while (sleep > 0) { + try { + Thread.sleep(500); + sleep -= 500; + subMonitor.subTask("Sleeping " + sleep); + } catch (InterruptedException e) { + } + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider2.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider2.java new file mode 100644 index 000000000..3bd6b11b2 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider2.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider2 extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/key.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + int sleep = new Random().nextInt(10000) + 1000; + while (sleep > 0) { + try { + Thread.sleep(500); + sleep -= 500; + subMonitor.subTask("Sleeping " + sleep); + } catch (InterruptedException e) { + } + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider3.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider3.java new file mode 100644 index 000000000..18ee0bf31 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider3.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider3 extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/ecf.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + int sleep = new Random().nextInt(10000) + 1000; + while (sleep > 0) { + try { + Thread.sleep(500); + sleep -= 500; + subMonitor.subTask("Sleeping " + sleep); + } catch (InterruptedException e) { + } + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider4.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider4.java new file mode 100644 index 000000000..d896afae1 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider4.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider4 extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/pin.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + int sleep = new Random().nextInt(10000) + 1000; + while (sleep > 0) { + try { + Thread.sleep(500); + sleep -= 500; + subMonitor.subTask("Sleeping " + sleep); + } catch (InterruptedException e) { + } + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider5.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider5.java new file mode 100644 index 000000000..cff85162c --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider5.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider5 extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/plugin.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + int sleep = new Random().nextInt(10000) + 1000; + while (sleep > 0) { + try { + Thread.sleep(500); + sleep -= 500; + subMonitor.subTask("Sleeping " + sleep); + } catch (InterruptedException e) { + } + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider6.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider6.java new file mode 100644 index 000000000..6626d1b59 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider6.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider6 extends org.eclipse.tips.core.TipProvider { + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/pydev.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider7.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider7.java new file mode 100644 index 000000000..f3fe1fdee --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/test/TestProvider7.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.java.java9.Tip1; +import org.eclipse.tips.examples.tipsframework.Navigate2Tip; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TestProvider7 extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/twitter.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage48; + } + + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + } + List<Tip> tips = new ArrayList<>(); + tips.add(new Tip1(getID())); + tips.add(new Navigate2Tip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public String getDescription() { + return "Test Provider " + getClass().getSimpleName(); + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +} diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/MediaWikiTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/MediaWikiTip.java new file mode 100644 index 000000000..b43867fe0 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/MediaWikiTip.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tips; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Date; + +import org.eclipse.tips.core.IUrlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; + +/** + * Specialisation of Tip that receives an URL of a mediawiki page (e.g. Eclipse + * wiki) and renders this URL as a tip. + * <p> + * For an example see: + * + * <a href= + * "https://wiki.eclipse.org/Tip_of_the_Day/Eclipse_Tips/Now_where_was_I">https://wiki.eclipse.org/Tip_of_the_Day/Eclipse_Tips/Now_where_was_I</a> + * + */ +public class MediaWikiTip extends Tip implements IUrlTip { + + private String fPageUrl; + private Date fCreationDate; + private String fSubject; + + /** + * Constructor. + * + * <p> + * For an example see: + * + * <a href= + * "https://wiki.eclipse.org/Tip_of_the_Day/Eclipse_Tips/Now_where_was_I">https://wiki.eclipse.org/Tip_of_the_Day/Eclipse_Tips/Now_where_was_I</a> + * </p> + * + * @param pProvider + * the {@link TipProvider} that created this Tip + * @param pPageUrl + * the Eclipse wiki page containing a simple tip + * @param pCreationDate + * creation date + * @param pSubject + * the tips' subject + */ + public MediaWikiTip(String providerId, String pPageUrl, Date pCreationDate, String pSubject) { + super(providerId); + fPageUrl = pPageUrl; + fCreationDate = pCreationDate; + fSubject = pSubject; + } + + @Override + public Date getCreationDate() { + return fCreationDate; + } + + @Override + public String getSubject() { + return fSubject; + } + + @Override + public URL getURL() { + try { + return new URL(fPageUrl.trim() + "?action=render"); + } catch (MalformedURLException e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/TwitterTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/TwitterTip.java new file mode 100644 index 000000000..0d1e2cbcc --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/TwitterTip.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tips; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Date; + +import org.eclipse.tips.core.IUrlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; + +/** + * Specialisation of Tip that receives an URL of a tweet in the constructor. The + * URL points directly to the tweet: + * <p> + * For an example see: <a href= + * "https://twitter.com/EclipseJavaIDE/status/919915440041840641">https://twitter.com/EclipseJavaIDE/status/919915440041840641</a> + * </p> + */ +public class TwitterTip extends Tip implements IUrlTip { + + private String fPageUrl; + private Date fCreationDate; + private String fSubject; + + /** + * Constructor. + * + * <p> + * For an example see: <a href= + * "https://twitter.com/EclipseJavaIDE/status/919915440041840641">https://twitter.com/EclipseJavaIDE/status/919915440041840641</a> + * </p> + * + * @param pProvider + * the {@link TipProvider} that created this Tip + * @param pTweetUrl + * the URL of the tweet + * @param pCreationDate + * creation date + * @param pSubject + * the tips' subject + */ + public TwitterTip(String providerId, String pTweetUrl, Date pCreationDate, String pSubject) { + super(providerId); + fPageUrl = pTweetUrl; + fCreationDate = pCreationDate; + fSubject = pSubject; + } + + @Override + public Date getCreationDate() { + return fCreationDate; + } + + @Override + public String getSubject() { + return fSubject; + } + + @Override + public URL getURL() { + try { + return new URL(fPageUrl); + } catch (MalformedURLException e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/package-info.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/package-info.java new file mode 100644 index 000000000..77276a13c --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tips/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Contains some example tip implementations, + * + */ +package org.eclipse.tips.examples.tips;
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/GithubTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/GithubTip.java new file mode 100644 index 000000000..cad686913 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/GithubTip.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.awt.Desktop; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipAction; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; + +public class GithubTip extends Tip implements IHtmlTip { + + public GithubTip(String providerId) { + super(providerId); + } + + @Override + public List<TipAction> getActions() { + Runnable runner = () -> Display.getDefault().asyncExec(() -> { + if (Platform.isRunning() && Platform.getWS().startsWith("gtk")) { + MessageDialog.openInformation(null, "Action", "Can't open a browser in GTK. It crashes the JVM."); + } else { + Desktop d = Desktop.getDesktop(); + try { + d.browse(new URI("https://github.com/wimjongman/tips")); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + } + }); + + ArrayList<TipAction> actions = new ArrayList<>(); + actions.add(new TipAction("Show in Github", "Opens a browser.", runner, null)); + return actions; + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("09/01/2018"); + } + + @Override + public String getSubject() { + return "On GitHub"; + } + + @Override + public String getHTML() { + return "<h2>Incubating on GitHub</h2>We are incubating this project on Github " + + "and we could use your help. Press the <b>More...</b> button to open the " + "GitHub repository. " + + "<br>" + "<br>" + "We are looking forward to your pull requests." + "<br>"; + } + + private TipImage fImage; + + @Override + public TipImage getImage() { + if (fImage == null) { + try { + fImage = new TipImage(new URL("https://assets-cdn.github.com/images/modules/logos_page/Octocat.png")) + .setAspectRatio(800, 665, true); + } catch (Exception e) { +// getProvider().getManager().log(LogUtil.error(getClass(), e)); + } + } + return fImage; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/MatrixRainTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/MatrixRainTip.java new file mode 100644 index 000000000..c672a1bec --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/MatrixRainTip.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.net.URL; +import java.util.Date; + +import org.eclipse.tips.core.IUrlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class MatrixRainTip extends Tip implements IUrlTip { + + public MatrixRainTip(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("09/01/2018"); + } + + @Override + public String getSubject() { + return "Welcome to the Matrix"; + } + + @Override + public URL getURL() { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + return bundle.getEntry("matrixrain/index.html"); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/Navigate1Tip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/Navigate1Tip.java new file mode 100644 index 000000000..e39a02e2f --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/Navigate1Tip.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipAction; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class Navigate1Tip extends Tip implements IHtmlTip { + + private TipImage fImage; + + @Override + public TipImage getImage() { + if (fImage == null) { + try { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + fImage = new TipImage(bundle.getEntry("images/tips/navigate1.png")).setAspectRatio(600, 200, true); + } catch (Exception e) { +// getProvider().getManager().log(LogUtil.info(getClass(), e)); + } + } + return fImage; + } + + public Navigate1Tip(String providerId) { + super(providerId); + } + + @Override + public List<TipAction> getActions() { + Runnable runnable = () -> Display.getDefault() + .syncExec(() -> MessageDialog.openConfirm(null, getSubject(), "We can do anything we want.")); + Runnable clock = () -> Display.getDefault().syncExec(() -> MessageDialog.openConfirm(null, getSubject(), + DateFormat.getTimeInstance().format(Calendar.getInstance().getTime()))); + Runnable runner2 = () -> Display.getDefault() + .syncExec(() -> MessageDialog.openConfirm(null, getSubject(), "Like open preferences...")); + ArrayList<TipAction> actions = new ArrayList<>(); + actions.add(new TipAction("Clock", "Some sort of clock action", clock, getImage("icons/clock.png"))); + actions.add( + new TipAction("Open Preferences", "Opens the preferences", runner2, getImage("icons/bug_link.png"))); + actions.add( + new TipAction("Cut or Paste", "Just another silly action", runnable, getImage("icons/lightbulb.png"))); + actions.add(new TipAction("Eclipse Rocks, Idea Scissors", "Paper", runnable, getImage("icons/cut.png"))); + actions.add(new TipAction("Totally Bonkers", "The quick brown fox", runnable, getImage("icons/notfound.png"))); + return actions; + } + + private TipImage getImage(String pIcon) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + return new TipImage(bundle.getEntry(pIcon)).setAspectRatio(1); + } catch (Exception e) { + return null; + } + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("09/01/2018"); + } + + @Override + public String getSubject() { + return "Navigate Tip 1"; + } + + @Override + public String getHTML() { + return "<h2>Navigating Tips</h2>You can navigate tips by using the button bar. " + + "<br><b>Next Tip</b><br>Navigates to the next tip." + + "<br><b>Previous Tip</b></br>Navigates to the previous tip." + + "<br><b>Close</b></br>Closes the Dialog (<b>Escape</b> does the same)." + + "<br><b>Show tips at startup</b><br/>A toggle to show this dialog when you start Eclipse." + + "<br><br>" + + "If a tip can do something special then the <b>More...</b> button is activated, like with this tip." + + "<br>Go on, press it!"; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/Navigate2Tip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/Navigate2Tip.java new file mode 100644 index 000000000..e997e5102 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/Navigate2Tip.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class Navigate2Tip extends Tip implements IHtmlTip { + + private TipImage fImage; + + public Navigate2Tip(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("09/01/2018"); + } + + @Override + public String getSubject() { + return "Navigate Tip 2"; + } + + @Override + public String getHTML() { + return "<h2>Navigating Tips</h2>You can activate other Tip Providers by clicking on the big icons below." + + "<br>" + + "You are currently looking at the Tips tips but as you can see there are other providers. Go ahead and" + + " select some of the other providers. If you click on the lightbulb below you will return to this tip.<br><br>"; + } + + @Override + public TipImage getImage() { + if (fImage == null) { + try { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + fImage = new TipImage(bundle.getEntry("images/tips/navigate2.png")).setAspectRatio(650, 220, true); + } catch (Exception e) { +// getProvider().getManager().log(LogUtil.info(getClass(), e)); + } + } + return fImage; + } + +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/StartingTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/StartingTip.java new file mode 100644 index 000000000..f55cdacd5 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/StartingTip.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.examples.DateUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class StartingTip extends Tip implements IHtmlTip { + + public StartingTip(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("09/01/2018"); + } + + @Override + public String getSubject() { + return "Opening the Tips Dialog"; + } + + @Override + public String getHTML() { + return "<h2>Opening the Tips Dialog</h2>The tips are started automatically at startup but you can switch this off." + + " In case the tips are not loaded at startup you can active the tips manually from the Help menu." + + "<br><br>" + "Press <b><i>Next Tip</i></b> to see how to navigate Tips.<br><br>"; + } + + private TipImage fImage; + + @Override + public TipImage getImage() { + if (fImage == null) { + try { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + fImage = new TipImage(bundle.getEntry("images/tips/starttip.gif")).setAspectRatio(780, 430, true); + } catch (Exception e) { +// getProvider().getManager().log(LogUtil.info(getClass(), e)); + } + } + return fImage; + } + +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/TipsTipProvider.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/TipsTipProvider.java new file mode 100644 index 000000000..ff6a1299f --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/TipsTipProvider.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.internal.LogUtil; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +public class TipsTipProvider extends org.eclipse.tips.core.TipProvider { + + private TipImage fImage64, fImage48; + + @Override + public TipImage getImage() { + if (fImage48 == null) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + try { + fImage48 = new TipImage(bundle.getEntry("icons/48/tips.png")).setAspectRatio(1); + } catch (IOException e) { + getManager().log(LogUtil.info(getClass(), e)); + } + } + return fImage48; + } + + @Override + public synchronized IStatus loadNewTips(IProgressMonitor pMonitor) { + SubMonitor subMonitor = SubMonitor.convert(pMonitor); + subMonitor.beginTask("Loading Tips", -1); + List<Tip> tips = new ArrayList<>(); + tips.add(new WelcomeTip(getID())); + tips.add(new StartingTip(getID())); + tips.add(new Navigate1Tip(getID())); + tips.add(new Navigate2Tip(getID())); + tips.add(new GithubTip(getID())); + tips.add(new MatrixRainTip(getID())); + setTips(tips); + subMonitor.done(); + return Status.OK_STATUS; + } + + @Override + public String getDescription() { + return "Tips about Tips"; + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/WelcomeTip.java b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/WelcomeTip.java new file mode 100644 index 000000000..f07436127 --- /dev/null +++ b/org.eclipse.tips.examples/src/org/eclipse/tips/examples/tipsframework/WelcomeTip.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.examples.tipsframework; + +import java.util.Date; + +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.examples.DateUtil; + +public class WelcomeTip extends Tip implements IHtmlTip { + + public WelcomeTip(String providerId) { + super(providerId); + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("09/01/2018"); + } + + @Override + public String getSubject() { + return "Welcome to the tips framework"; + } + + @Override + public String getHTML() { + return "<h2>Welcome to the Tips Framework</h2>It can show tips from various tip providers. This provider has tips about tips which will show you how to navigate this UI." + + " The dialog is this Tip UI. Tips appear here in various forms. They can come from Twitter, a Wiki, a Website, a file or even from Java, like this one." + + "<br><br>" + "Press <b><i>Next Tip</i></b> to see how to start tips manually."; + } + + @Override + public TipImage getImage() { + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.feature/.gitignore b/org.eclipse.tips.feature/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/org.eclipse.tips.feature/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/org.eclipse.tips.feature/.project b/org.eclipse.tips.feature/.project new file mode 100644 index 000000000..a59eaefd9 --- /dev/null +++ b/org.eclipse.tips.feature/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tips.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.tips.feature/build.properties b/org.eclipse.tips.feature/build.properties new file mode 100644 index 000000000..96dd6d0f0 --- /dev/null +++ b/org.eclipse.tips.feature/build.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2018 Remain Software +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# wim.jongman@remainsoftware.com - initial API and implementation +############################################################################### +bin.includes = feature.xml,\ + epl-v10.html,\ + feature.properties,\ + license.html diff --git a/org.eclipse.tips.feature/feature.properties b/org.eclipse.tips.feature/feature.properties new file mode 100644 index 000000000..6b58e96f8 --- /dev/null +++ b/org.eclipse.tips.feature/feature.properties @@ -0,0 +1,156 @@ +############################################################################### +# Copyright (c) 2018, Wim Jongman Remain Software. +# 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 +############################################################################### + +featureName=Tip of the Day UI Feature +providerName=Remain Software + +updateSiteName=Eclipse Update Site + +# description property - text of the "Feature Description" +description=Contains the Eclipse Tips framework. +################ end of description property ################################## + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2018 Wim Jongman, Remain Software\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License v1.0\n\ +which accompanies this distribution, and is available at\n\ +http://www.eclipse.org/legal/epl-v10.html\n +################ end of copyright property #################################### + +# "licenseURL" property - URL of the "Feature License" +# do not translate value - just change to point to a locale-specific HTML page +licenseURL=license.html + +# "license" property - text of the "Feature Update License" +# should be plain text version of license agreement pointed to be "licenseURL" +license=\ +Eclipse Foundation Software User Agreement\n\ +April 9, 2014\n\ +\n\ +Usage Of Content\n\ +\n\ +THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\ +OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\ +USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\ +AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\ +NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU\n\ +AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\ +AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\ +OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE\n\ +TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\ +OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\ +BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\ +\n\ +Applicable Licenses\n\ +\n\ +Unless otherwise indicated, all Content made available by the\n\ +Eclipse Foundation is provided to you under the terms and conditions of\n\ +the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\ +provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\ +For purposes of the EPL, "Program" will mean the Content.\n\ +\n\ +Content includes, but is not limited to, source code, object code,\n\ +documentation and other files maintained in the Eclipse Foundation source code\n\ +repository ("Repository") in software modules ("Modules") and made available\n\ +as downloadable archives ("Downloads").\n\ +\n\ +\t- Content may be structured and packaged into modules to facilitate delivering,\n\ +\t extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\ +\t plug-in fragments ("Fragments"), and features ("Features").\n\ +\t- Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\ +\t in a directory named "plugins".\n\ +\t- A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\ +\t Each Feature may be packaged as a sub-directory in a directory named "features".\n\ +\t Within a Feature, files named "feature.xml" may contain a list of the names and version\n\ +\t numbers of the Plug-ins and/or Fragments associated with that Feature.\n\ +\t- Features may also include other Features ("Included Features"). Within a Feature, files\n\ +\t named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\ +\n\ +The terms and conditions governing Plug-ins and Fragments should be\n\ +contained in files named "about.html" ("Abouts"). The terms and\n\ +conditions governing Features and Included Features should be contained\n\ +in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\ +Licenses may be located in any directory of a Download or Module\n\ +including, but not limited to the following locations:\n\ +\n\ +\t- The top-level (root) directory\n\ +\t- Plug-in and Fragment directories\n\ +\t- Inside Plug-ins and Fragments packaged as JARs\n\ +\t- Sub-directories of the directory named "src" of certain Plug-ins\n\ +\t- Feature directories\n\ +\n\ +Note: if a Feature made available by the Eclipse Foundation is installed using the\n\ +Provisioning Technology (as defined below), you must agree to a license ("Feature \n\ +Update License") during the installation process. If the Feature contains\n\ +Included Features, the Feature Update License should either provide you\n\ +with the terms and conditions governing the Included Features or inform\n\ +you where you can locate them. Feature Update Licenses may be found in\n\ +the "license" property of files named "feature.properties" found within a Feature.\n\ +Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\ +terms and conditions (or references to such terms and conditions) that\n\ +govern your use of the associated Content in that directory.\n\ +\n\ +THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\ +TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\ +SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\ +\n\ +\t- Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\ +\t- Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\ +\t- Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\ +\t- Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\ +\t- Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\ +\n\ +IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\ +TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\ +is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\ +govern that particular Content.\n\ +\n\ +\n\Use of Provisioning Technology\n\ +\n\ +The Eclipse Foundation makes available provisioning software, examples of which include,\n\ +but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\ +the purpose of allowing users to install software, documentation, information and/or\n\ +other materials (collectively "Installable Software"). This capability is provided with\n\ +the intent of allowing such users to install, extend and update Eclipse-based products.\n\ +Information about packaging Installable Software is available at\n\ +http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\ +\n\ +You may use Provisioning Technology to allow other parties to install Installable Software.\n\ +You shall be responsible for enabling the applicable license agreements relating to the\n\ +Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\ +in accordance with the Specification. By using Provisioning Technology in such a manner and\n\ +making it available in accordance with the Specification, you further acknowledge your\n\ +agreement to, and the acquisition of all necessary rights to permit the following:\n\ +\n\ +\t1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\ +\t the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\ +\t extending or updating the functionality of an Eclipse-based product.\n\ +\t2. During the Provisioning Process, the Provisioning Technology may cause third party\n\ +\t Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\ +\t3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\ +\t govern the use of the Installable Software ("Installable Software Agreement") and such\n\ +\t Installable Software Agreement shall be accessed from the Target Machine in accordance\n\ +\t with the Specification. Such Installable Software Agreement must inform the user of the\n\ +\t terms and conditions that govern the Installable Software and must solicit acceptance by\n\ +\t the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\ +\t indication of agreement by the user, the provisioning Technology will complete installation\n\ +\t of the Installable Software.\n\ +\n\ +Cryptography\n\ +\n\ +Content may contain encryption software. The country in which you are\n\ +currently may have restrictions on the import, possession, and use,\n\ +and/or re-export to another country, of encryption software. BEFORE\n\ +using any encryption software, please check the country's laws,\n\ +regulations and policies concerning the import, possession, or use, and\n\ +re-export of encryption software, to see if this is permitted.\n\ +\n\ +Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n +########### end of license property ########################################## diff --git a/org.eclipse.tips.feature/feature.xml b/org.eclipse.tips.feature/feature.xml new file mode 100644 index 000000000..b1f0efc37 --- /dev/null +++ b/org.eclipse.tips.feature/feature.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> +<feature + id="org.eclipse.tips.feature" + label="%featureName" + version="0.1.0.qualifier" + provider-name="%providerName" + license-feature="org.eclipse.license" + license-feature-version="0.0.0"> + + <description> + %description + </description> + + <copyright> + %copyright + </copyright> + + <license url="%licenseURL"> + %license + </license> + + <plugin + id="org.eclipse.tips.ui" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.tips.core" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.tips.json" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + +</feature> diff --git a/org.eclipse.tips.feature/pom.xml b/org.eclipse.tips.feature/pom.xml new file mode 100644 index 000000000..3ce586521 --- /dev/null +++ b/org.eclipse.tips.feature/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<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>eclipse.platform.ua</groupId> + <artifactId>eclipse.platform.ua</artifactId> + <version>4.8.0-SNAPSHOT</version> + <relativePath>../../</relativePath> + </parent> + <groupId>org.eclipse.ui</groupId> + <artifactId>org.eclipse.tips.feature</artifactId> + <version>0.1.0-SNAPSHOT</version> + <packaging>eclipse-feature</packaging> +</project> diff --git a/org.eclipse.tips.ide/.classpath b/org.eclipse.tips.ide/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/org.eclipse.tips.ide/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.tips.ide/.gitignore b/org.eclipse.tips.ide/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.eclipse.tips.ide/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.eclipse.tips.ide/.project b/org.eclipse.tips.ide/.project new file mode 100644 index 000000000..c1911190d --- /dev/null +++ b/org.eclipse.tips.ide/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tips.ide</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.tips.ide/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tips.ide/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/org.eclipse.tips.ide/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.eclipse.tips.ide/META-INF/MANIFEST.MF b/org.eclipse.tips.ide/META-INF/MANIFEST.MF new file mode 100644 index 000000000..35e3add48 --- /dev/null +++ b/org.eclipse.tips.ide/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: IDE Enablement for Tip of the Day +Bundle-SymbolicName: org.eclipse.tips.ide;singleton:=true +Bundle-Version: 0.1.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.ui;bundle-version="3.109.0", + org.eclipse.core.runtime;bundle-version="3.13.0", + org.eclipse.core.expressions;bundle-version="3.6.0", + org.eclipse.e4.ui.workbench;bundle-version="1.5.1", + org.eclipse.tips.core;bundle-version="0.1.0", + org.eclipse.tips.ui;bundle-version="0.1.0" +Export-Package: org.eclipse.tips.ide.internal;x-internal:=true +Automatic-Module-Name: org.eclipse.tips.ide diff --git a/org.eclipse.tips.ide/build.properties b/org.eclipse.tips.ide/build.properties new file mode 100644 index 000000000..acbb37a1e --- /dev/null +++ b/org.eclipse.tips.ide/build.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2018 Remain Software +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# wim.jongman@remainsoftware.com - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + icons/ diff --git a/org.eclipse.tips.ide/icons/lightbulb.png b/org.eclipse.tips.ide/icons/lightbulb.png Binary files differnew file mode 100644 index 000000000..d22fde8ba --- /dev/null +++ b/org.eclipse.tips.ide/icons/lightbulb.png diff --git a/org.eclipse.tips.ide/plugin.xml b/org.eclipse.tips.ide/plugin.xml new file mode 100644 index 000000000..9fc3c7f66 --- /dev/null +++ b/org.eclipse.tips.ide/plugin.xml @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.4"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<plugin> + <extension + point="org.eclipse.ui.startup"> + <startup + class="org.eclipse.tips.ide.internal.Startup"> + </startup> + </extension> + <extension + point="org.eclipse.ui.commands"> + <command + defaultHandler="org.eclipse.tips.ide.internal.TipsHandler" + id="org.eclipse.tips.ide.command.open" + name="Tip of the Day"> + </command> + <command + id="org.eclipse.tips.ide.command.trim.open" + name="Tip of the Day"> + </command> + </extension> + <extension + point="org.eclipse.ui.menus"> + <menuContribution + allPopups="false" + locationURI="menu:help?before=tipsAndTricks"> + <command + commandId="org.eclipse.tips.ide.command.open" + icon="icons/lightbulb.png" + id="org.eclipse.tips.ide.tip.menu" + label="Tip of the Day" + style="push"> variable="newtips"> + </command> + </menuContribution> + <menuContribution + allPopups="false" + locationURI="toolbar:org.eclipse.ui.trim.status"> + <toolbar + id="org.eclipse.tips.ide.toolbar.status" + label="Tip of the Day Toolbar"> + <command + commandId="org.eclipse.tips.ide.command.trim.open" + icon="icons/lightbulb.png" + id="org.eclipse.tips.ide.tip.tool" + label="Tip of the Day" + style="push"> + <visibleWhen + checkEnabled="false"> + <with + variable="newtips"> + <equals + value="true"> + </equals> + </with> + </visibleWhen> + </command> + </toolbar> + </menuContribution> + </extension> + <extension + point="org.eclipse.ui.themes"> + <themeElementCategory + id="org.eclipse.tips.presentation" + label="Tip of the Day"> + </themeElementCategory> + <fontDefinition + categoryId="org.eclipse.tips.presentation" + defaultsTo="org.eclipse.jface.textfont" + id="org.eclipse.tips.browser.font" + label="Browser font"> + <description> + The browser font (may be overridden by HTML and CSS) + </description> + </fontDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.browser.background.color" + label="Browser background color" + value="COLOR_WHITE"> + <description> + The browser background color (may be overridden by HTML and CSS) + </description> + </colorDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.browser.foreground.color" + label="Browser foreground color" + value="COLOR_BLACK"> + <description> + The browser foreground color (may be overridden by HTML and CSS) + </description> + </colorDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.hover.color" + label="Slider button hover color" + value="COLOR_GRAY"> + <description> + The background color of the button when the mouse hovers over the button. + </description> + </colorDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.selection.color" + label="Slider button selection color" + value="COLOR_TITLE_BACKGROUND"> + <description> + The color of the button when this is the selected button. + </description> + </colorDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.unreadTipCount.background.color" + label="Unread tip counter background color" + value="COLOR_RED"> + <description> + The background color of the tip counter badge when in unread mode. + </description> + </colorDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.unreadTipCount.foreground.color" + label="Unread tip counter foreground color" + value="COLOR_WHITE"> + <description> + The foreground color of the tip counter badge when in unread mode. + </description> + </colorDefinition> + <fontDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.badge.font" + label="Slider badge font" + value="Sans-bold-10"> + <description> + The counter badge font. + </description> + </fontDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.tipCount.background.color" + label="Tip counter background color" + value="COLOR_DARK_GREEN"> + <description> + The background color of the counter badge when not in unread mode. + </description> + </colorDefinition> + <colorDefinition + categoryId="org.eclipse.tips.presentation" + id="org.eclipse.tips.slider.tipCount.foreground.color" + label="Tip counter foreground color" + value="COLOR_WHITE"> + <description> + The background color of the tip counter badge when not in unread mode. + </description> + </colorDefinition> + </extension> + <extension + point="org.eclipse.ui.handlers"> + <handler + class="org.eclipse.tips.ide.internal.TipsHandler" + commandId="org.eclipse.tips.ide.command.trim.open"> + <activeWhen> + <with + variable="newtips"> + <equals + value="true"> + </equals> + </with> + </activeWhen> + </handler> + </extension> + <extension + point="org.eclipse.core.runtime.preferences"> + <initializer + class="org.eclipse.tips.ide.internal.Preferences"> + </initializer> + </extension> +</plugin> diff --git a/org.eclipse.tips.ide/pom.xml b/org.eclipse.tips.ide/pom.xml new file mode 100644 index 000000000..d7389d0a5 --- /dev/null +++ b/org.eclipse.tips.ide/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<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>eclipse.platform.ua</groupId> + <artifactId>eclipse.platform.ua</artifactId> + <version>4.8.0-SNAPSHOT</version> + </parent> + <groupId>org.eclipse.ui</groupId> + <artifactId>org.eclipse.tips.ide</artifactId> + <version>0.1.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> +</project> diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Constants.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Constants.java new file mode 100644 index 000000000..ffe557322 --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Constants.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +/** + * Shared constants. + * + */ +public class Constants { + + /** + * The ID of this bundle + */ + public static final String BUNDLE_ID = "org.eclipse.tips.ide"; + + /** + * Dialog. menu and tool item icon. + */ + public static final String ICON = "icons/lightbulb.png"; + + /** + * The workbench variable to be used on core expressions. + */ + public static final String SOURCE_UNREAD_TIPS = "newtips"; +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/IDETipManager.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/IDETipManager.java new file mode 100644 index 000000000..b4652412d --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/IDETipManager.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.eclipse.core.expressions.EvaluationResult; +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.ExpressionConverter; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.tips.core.ITipManager; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipManager; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.ui.DefaultTipManager; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.services.IEvaluationService; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Class to manage the tip providers and start the tip of the day UI. + */ +@SuppressWarnings("restriction") +public class IDETipManager extends DefaultTipManager { + + private TipSourceProvider fSourceProvider = new TipSourceProvider(); + + private List<Integer> fReadTips = new ArrayList<>(); + + private boolean fNewTips; + + private boolean fSourceProviderAdded; + + private static IDETipManager instance = new IDETipManager(); + + /** + * @return the tip manager instance. + */ + public static synchronized IDETipManager getInstance() { + if (instance.isDisposed()) { + instance = new IDETipManager(); + } + return instance; + } + + private IDETipManager() { + } + + @Override + public ITipManager register(TipProvider provider) { + super.register(provider); + load(provider); + return this; + } + + private void load(TipProvider provider) { + Job job = new Job("Loading " + provider.getDescription()) { + @Override + protected IStatus run(IProgressMonitor monitor) { + return provider.loadNewTips(monitor); + } + }; + job.addJobChangeListener(new ProviderLoadJobChangeListener(this, provider)); + job.schedule(); + } + + @Override + public TipManager open(boolean startUp) { + // if (isOpen()) { + // return this; + // } + if (!fSourceProviderAdded) { + IEvaluationService evaluationService = PlatformUI.getWorkbench().getService(IEvaluationService.class); + evaluationService.addSourceProvider(fSourceProvider); + fSourceProviderAdded = true; + } + return super.open(startUp); + } + + /** + * Calculates the new tip count to find if we need to expose the status trim + * tool item. + * + * @param newTips + */ + private void refreshUI(boolean newTips) { + Job job = new Job("Tip of the Day..") { + @Override + protected IStatus run(IProgressMonitor monitor) { + setNewTips(newTips); + return Status.OK_STATUS; + } + }; + job.schedule(); + } + + @Override + public boolean isRunAtStartup() { + return Preferences.isRunAtStartup(); + } + + @Override + public TipManager setRunAtStartup(boolean runAtStartup) { + Preferences.setRunAtStartup(runAtStartup); + return this; + } + + @Override + public boolean mustServeReadTips() { + return Preferences.isServeReadTips(); + } + + @Override + public TipManager setServeReadTips(boolean serveRead) { + Preferences.setServeReadTips(serveRead); + return this; + } + + @Override + public ITipManager log(IStatus status) { + if (status.matches(IStatus.ERROR | IStatus.WARNING)) { + Bundle bundle = FrameworkUtil.getBundle(getClass()); + Platform.getLog(bundle).log(status); + } + if (System.getProperty("org.eclipse.tips.consolelog") != null) { + System.out.println(status.toString()); + } + return this; + } + + @Override + public boolean isRead(Tip tip) { + if (fReadTips.contains(new Integer(tip.hashCode()))) { + return true; + } + return false; + } + + @Override + public TipManager setAsRead(Tip tip) { + if (!isRead(tip)) { + fReadTips.add(new Integer(tip.hashCode())); + } + return this; + } + + protected synchronized IDETipManager setNewTips(boolean newTips) { + if (fNewTips != newTips) { + fNewTips = newTips; + fSourceProvider.setStatus(fNewTips); + } + return this; + } + + @Override + public void dispose() { + try { + boolean newTips = getProviders().stream().filter(p -> !p.getTips(true).isEmpty()).count() > 0; + refreshUI(newTips); + } finally { + super.dispose(); + } + } + + /** + * {@inheritDoc} + * <p> + * The weight is determined by the enablement expression. If there is no + * enablement expression then the weight is 20. If there is a non matching + * enablement then the weight is 30. If there is a matching enablement then the + * weight is 10. + * + * @param provider + * the provider + * + * @return the weight + */ + @Override + public int getPriority(TipProvider provider) { + log(LogUtil.info("Evaluating expression: " + provider.getExpression())); + int priority = doGetPriority(provider.getExpression()); + log(LogUtil.info("Evaluating expression done. Priority: " + priority)); + return priority; + } + + private int doGetPriority(String expression) { + if (expression == null) { + return 20; + } + try { + String myExpression = "<enablement>" + expression + "</enablement>"; + myExpression = "<?xml version=\"1.0\"?>" + myExpression; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + Document doc = factory.newDocumentBuilder().parse(new ByteArrayInputStream(myExpression.getBytes())); + Element element = (Element) doc.getElementsByTagName("enablement").item(0); + Expression expressionObj = ExpressionConverter.getDefault().perform(element); + final EvaluationResult result = expressionObj.evaluate(getEvaluationContext()); + if (result == EvaluationResult.TRUE) { + return 10; + } else { + return 30; + } + } catch (Exception e) { + log(LogUtil.error(e)); + return 20; + } + } + + /** + * + * @return Evaluation Context to evaluate core expression + */ + private static IEvaluationContext getEvaluationContext() { + IEvaluationService evalService = PlatformUI.getWorkbench().getService(IEvaluationService.class); + IEvaluationContext currentState = evalService.getCurrentState(); + return currentState; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Preferences.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Preferences.java new file mode 100644 index 000000000..d03451bd0 --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Preferences.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.core.runtime.preferences.ConfigurationScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.osgi.service.prefs.BackingStoreException; + +/** + * Internal class to store preferences. + * + */ +public class Preferences extends AbstractPreferenceInitializer { + + /** + * Preference store key to indicate showing tips at startup. + */ + public static final String PREF_RUN_AT_STARTUP = "activate_at_startup"; + + /** + * Preference store key to indicate serving tips that the user as already seen. + */ + public static final String PREF_SERVE_READ_TIPS = "serve_read_tips"; + + public Preferences() { + } + + @Override + public void initializeDefaultPreferences() { + IEclipsePreferences node = getPreferences(); + node.putBoolean(PREF_RUN_AT_STARTUP, true); + node.putBoolean(PREF_SERVE_READ_TIPS, false); + try { + node.flush(); + } catch (BackingStoreException e) { + throw new RuntimeException(e); + } + } + + public static IEclipsePreferences getPreferences() { + IEclipsePreferences node = ConfigurationScope.INSTANCE.getNode(Constants.BUNDLE_ID); + return node; + } + + public static boolean isRunAtStartup() { + return getPreferences().getBoolean(PREF_RUN_AT_STARTUP, true); + } + + public static boolean isServeReadTips() { + return getPreferences().getBoolean(PREF_SERVE_READ_TIPS, false); + } + + public static void setRunAtStartup(boolean runAtStartup) { + IEclipsePreferences node = getPreferences(); + node.putBoolean(PREF_RUN_AT_STARTUP, runAtStartup); + try { + node.flush(); + } catch (BackingStoreException e) { + throw new RuntimeException(e); + } + } + + public static void setServeReadTips(boolean serveReadTips) { + IEclipsePreferences node = getPreferences(); + node.putBoolean(PREF_SERVE_READ_TIPS, serveReadTips); + try { + node.flush(); + } catch (BackingStoreException e) { + throw new RuntimeException(e); + } + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/ProviderLoadJobChangeListener.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/ProviderLoadJobChangeListener.java new file mode 100644 index 000000000..36af35e29 --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/ProviderLoadJobChangeListener.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipProvider; + +/** + * + * Internal class to listen to async provider load completions. + * + */ +public class ProviderLoadJobChangeListener extends JobChangeAdapter { + + private IDETipManager fManager; + private TipProvider fProvider; + + public ProviderLoadJobChangeListener(IDETipManager manager, TipProvider provider) { + fManager = manager; + fProvider = provider; + } + + /** + * {@inheritDoc} + * <p> + * If this provider has new tips then the {@link IDETipManager} gets a callback + * to update the UI. + * + * @see IDETipManager#setNewTips(boolean) + */ + @Override + public void done(IJobChangeEvent event) { + for (Tip tip : fProvider.getTips(false)) { + if (!fManager.isRead(tip)) { + fManager.setNewTips(true); + return; + } + } + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Startup.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Startup.java new file mode 100644 index 000000000..8c3b67b9b --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/Startup.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.ui.IStartup; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.UIJob; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * Early startup to run the TipManager in the IDE. + * + */ +public class Startup implements IStartup { + + @Override + public void earlyStartup() { + loadProviders(); + openManager(); + } + + /** + * Reloads the tip providers. + */ + public static void loadProviders() { + IConfigurationElement[] elements = Platform.getExtensionRegistry() + .getConfigurationElementsFor("org.eclipse.tips.core.tips"); + for (IConfigurationElement element : elements) { + if (element.getName().equals("provider")) { + try { + TipProvider provider = (TipProvider) element.createExecutableExtension("class"); + provider.setExpression(getExpression(element)); + IDETipManager.getInstance().register(provider); + } catch (CoreException e) { + log(e); + } + } + } + } + + /** + * @return the core expression + */ + private static String getExpression(IConfigurationElement element) { + IConfigurationElement[] enablements = element.getChildren("enablement"); + if (enablements.length == 0) { + return null; + } + IConfigurationElement enablement = enablements[0]; + String result = getXML(enablement.getChildren()); + return result; + } + + private static String getXML(IConfigurationElement[] children) { + String result = ""; + for (IConfigurationElement element : children) { + IConfigurationElement[] myChildren = element.getChildren(); + result += "<" + element.getName() + " " + getXMLAttributes(element) + ">"; + if (myChildren.length > 0) { + result += getXML(myChildren); + } else { + String value = element.getValue(); + result += value == null ? "" : value; + } + result += "</" + element.getName() + ">"; + } + return result; + } + + private static String getXMLAttributes(IConfigurationElement element) { + String result = ""; + for (String name : element.getAttributeNames()) { + result += name; + result += "=\""; + result += element.getAttribute(name); + result += "\" "; + } + return result; + } + + private static void openManager() { + UIJob job = new UIJob(PlatformUI.getWorkbench().getDisplay(), "Tip of the Day") { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + IDETipManager.getInstance().open(true); + return Status.OK_STATUS; + } + }; + job.schedule(); + } + + private static void log(CoreException e) { + Bundle bundle = FrameworkUtil.getBundle(Startup.class); + Status status = new Status(IStatus.ERROR, bundle.getSymbolicName(), e.getMessage(), e); + Platform.getLog(bundle).log(status); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/TipSourceProvider.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/TipSourceProvider.java new file mode 100644 index 000000000..3877c8c73 --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/TipSourceProvider.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ui.AbstractSourceProvider; +import org.eclipse.ui.ISources; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.UIJob; + +/** + * Internal class to source a new boolean variable in the IDE called "newtips". + * + */ +public class TipSourceProvider extends AbstractSourceProvider { + private boolean fNewTips; + + public TipSourceProvider() { + } + + @Override + public void dispose() { + } + + @Override + public Map<?, ?> getCurrentState() { + Map<Object, Object> currentState = new HashMap<>(); + currentState.put(Constants.SOURCE_UNREAD_TIPS, new Boolean(fNewTips)); + return currentState; + } + + @Override + public String[] getProvidedSourceNames() { + return new String[] { Constants.SOURCE_UNREAD_TIPS }; + } + + /** + * Propagate the new status of the <code>newtips</code> variable but always + * layouts all workbench windows to update the trim status. + * + * @param newTips + * true if there are new tips, false if there are no more new tips. + */ + public synchronized void setStatus(boolean newTips) { + boolean changed = fNewTips != newTips; + if (changed) { + fNewTips = newTips; + } + layoutWorkbench(changed); + } + + private void layoutWorkbench(boolean changed) { + UIJob job = new UIJob(PlatformUI.getWorkbench().getDisplay(), "Tip of the Day. Layout Shell") { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + if (changed) { + fireSourceChanged(ISources.ACTIVE_WORKBENCH_WINDOW, getCurrentState()); + } + for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) { + System.out.println("layout on " + window + " -> " + fNewTips); + window.getShell().layout(true, true); + } + return Status.OK_STATUS; + } + }; + job.schedule(5000); // allow the workbench to settle in. + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/TipsHandler.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/TipsHandler.java new file mode 100644 index 000000000..901823467 --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/TipsHandler.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ide.internal; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +/** + * Internal class to open the IDE Tip Dialog. + * + */ +public class TipsHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + Startup.loadProviders(); + IDETipManager.getInstance().open(false); + return null; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/package-info.java b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/package-info.java new file mode 100644 index 000000000..93f73dde0 --- /dev/null +++ b/org.eclipse.tips.ide/src/org/eclipse/tips/ide/internal/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Internal implementation of the TipManager for the Eclipse IDE. You can use + * these classes to see how we have implemented our TipManager and then create + * your own. + */ +package org.eclipse.tips.ide.internal;
\ No newline at end of file diff --git a/org.eclipse.tips.tests/.classpath b/org.eclipse.tips.tests/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/org.eclipse.tips.tests/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.tips.tests/.gitignore b/org.eclipse.tips.tests/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.eclipse.tips.tests/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.eclipse.tips.tests/.project b/org.eclipse.tips.tests/.project new file mode 100644 index 000000000..50e9e6052 --- /dev/null +++ b/org.eclipse.tips.tests/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tips.tests</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.tips.tests/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tips.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/org.eclipse.tips.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.eclipse.tips.tests/META-INF/MANIFEST.MF b/org.eclipse.tips.tests/META-INF/MANIFEST.MF new file mode 100644 index 000000000..f1959ea29 --- /dev/null +++ b/org.eclipse.tips.tests/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tip of the Day Tests +Bundle-SymbolicName: org.eclipse.tips.tests +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: Eclipse +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.junit;bundle-version="4.12.0", + org.eclipse.tips.examples;bundle-version="0.1.0", + org.eclipse.tips.ide;bundle-version="0.1.0", + org.eclipse.core.runtime;bundle-version="3.13.0", + org.eclipse.swt, + org.eclipse.jface;bundle-version="3.13.2", + org.eclipse.tips.core;bundle-version="0.1.0", + org.eclipse.tips.ui;bundle-version="0.1.0", + org.eclipse.tips.json;bundle-version="0.1.0" +Automatic-Module-Name: org.eclipse.tips.tests diff --git a/org.eclipse.tips.tests/build.properties b/org.eclipse.tips.tests/build.properties new file mode 100644 index 000000000..07f663ae2 --- /dev/null +++ b/org.eclipse.tips.tests/build.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2018 Remain Software +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# wim.jongman@remainsoftware.com - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.eclipse.tips.tests/pom.xml b/org.eclipse.tips.tests/pom.xml new file mode 100644 index 000000000..45d395555 --- /dev/null +++ b/org.eclipse.tips.tests/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<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>eclipse.platform.ua</groupId> + <artifactId>eclipse.platform.ua</artifactId> + <version>4.8.0-SNAPSHOT</version> + <relativePath>../../</relativePath> + </parent> + <groupId>org.eclipse.ui</groupId> + <artifactId>org.eclipse.tips.tests</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>eclipse-test-plugin</packaging> +</project> diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/JsonTestProvider.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/JsonTestProvider.java new file mode 100644 index 000000000..8c5829a26 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/JsonTestProvider.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import java.net.MalformedURLException; + +import org.eclipse.tips.json.JsonTipProvider; + +public class JsonTestProvider extends JsonTipProvider { + + public JsonTestProvider() throws MalformedURLException { + setJsonUrl("https://raw.githubusercontent.com/wimjongman/jsontips/master/photon/m3tips.json"); + } + + @Override + public String getID() { + return getClass().getName(); + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTip.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTip.java new file mode 100644 index 000000000..8c0b50b84 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTip.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import java.util.Date; + +import org.eclipse.tips.ui.internal.util.DateUtil; + +public class TestTip extends Tip implements IHtmlTip { + + private String fSubject; + private String fHTML; + + public TestTip(String providerId, String html, String subject) { + super(providerId); + fHTML = html; + fSubject = subject; + } + + @Override + public Date getCreationDate() { + return DateUtil.getDateFromYYMMDD("31/12/1964"); + } + + @Override + public String getHTML() { + return fHTML; + } + + @Override + public String getSubject() { + return fSubject; + } + + @Override + public TipImage getImage() { + return null; + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTipManager.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTipManager.java new file mode 100644 index 000000000..59ab3f1d4 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTipManager.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; + +public class TestTipManager extends TipManager { + + private boolean fShouldRun = true; + private List<Integer> fReadList = new ArrayList<>(); + + @Override + public TipManager setRunAtStartup(boolean shouldRun) { + fShouldRun = shouldRun; + return this; + } + + @Override + public boolean isRunAtStartup() { + return fShouldRun; + } + + @Override + public ITipManager register(TipProvider provider) { + super.register(provider); + load(provider); + return this; + } + + private void load(TipProvider provider) { + provider.loadNewTips(new NullProgressMonitor()); + } + + @Override + public boolean isRead(Tip tip) { + return fReadList.contains(tip.hashCode()); + } + + @Override + public TipManager setAsRead(Tip tip) { + fReadList.remove((Integer) tip.hashCode()); + fReadList.add(tip.hashCode()); + return this; + } + + @Override + public ITipManager log(IStatus status) { + System.out.println(status.toString()); + return this; + } + + @Override + public TipManager open(boolean startUp) { + return this; + } + + @Override + public int getPriority(TipProvider provider) { + return 20; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTipProvider.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTipProvider.java new file mode 100644 index 000000000..74423bf17 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TestTipProvider.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import java.util.Collections; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tips.ui.internal.util.ImageUtil; +import org.eclipse.tips.ui.internal.util.ResourceManager; + +public class TestTipProvider extends TipProvider { + + private static TipImage image; + + @Override + public String getDescription() { + return "Test Tip Provider"; + } + + @Override + public String getID() { + return getClass().getName(); + } + + @Override + public TipImage getImage() { + if (image == null) { + Image pluginImage = ResourceManager.getPluginImage("org.eclipse.tips.examples", "icons/48/c++.png"); + String base64 = ImageUtil.decodeFromImage(pluginImage, SWT.IMAGE_PNG); + image = new TipImage(base64); + } + return image; + } + + @Override + public IStatus loadNewTips(IProgressMonitor monitor) { + setTips(Collections.emptyList()); + return Status.OK_STATUS; + } + + @Override + public void dispose() { + + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipImageBas64Test.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipImageBas64Test.java new file mode 100644 index 000000000..a1e575f70 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipImageBas64Test.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import static org.junit.Assert.assertTrue; + +import org.eclipse.core.runtime.AssertionFailedException; +import org.junit.Test; + +public class TipImageBas64Test { + + private static final String BASE64 = "data:image/png;base64,thequickbrownfox"; + private static final String BASE64WRONG = "date:image/png;base64,thequickbrownfox"; + private static final String BASE64WRONG2 = "data:image/plip ;base64,thequickbrownfox"; + + private TipImage getTipImage() { + return new TipImage(BASE64); + } + + @Test(expected = AssertionFailedException.class) + public void testAssertHeight() { + new TipImage(BASE64).setAspectRatio(1000, 0, false); + } + + @Test(expected = AssertionFailedException.class) + public void testAssertWidth() { + new TipImage(BASE64).setAspectRatio(0, 100, false); + } + + @Test + public void testSetExtension() { + // assertTrue(getTipImage().getIMGAttributes(19, 10).contains("png")); + } + + @Test + public void testSetExtension2() { + // assertTrue(getTipImage().setExtension("bmp").getBase64Image().contains("bmp")); + // assertTrue(getTipImage().getIMGAttributes(19, 10).contains("png")); + } + + @Test + public void testGetIMGAttributes() { + String result = getTipImage().setAspectRatio(1.5).getIMGAttributes(740, 370).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"555\" height=\"370\"")); + } + + @Test + public void testGetBase64() { + assertTrue(getTipImage().getBase64Image().equals(BASE64)); + } + + @Test + public void testSetAspectRatioDouble() { + String result = getTipImage().setAspectRatio(1.5).getIMGAttributes(740, 370).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"555\" height=\"370\"")); + } + + @Test + public void testSetAspectRatioIntIntFalse() { + String result = getTipImage().setAspectRatio(200, 50, false).getIMGAttributes(100, 100).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"100\" height=\"25\"")); + } + + @Test + public void testSetAspectRatioIntIntTrue() { + String result = getTipImage().setAspectRatio(400, 300, true).getIMGAttributes(740, 370).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"400\" height=\"300\"")); + } + + @Test + public void testSetMaxHeight() { + String imgAttributes = new TipImage(BASE64).setAspectRatio(2).setMaxHeight(300).getIMGAttributes(200, 200); + assertTrue(imgAttributes, imgAttributes.trim().equalsIgnoreCase("width=\"200\" height=\"100\"")); + } + + @Test + public void testSetMaxWidth() { + String imgAttributes = new TipImage(BASE64).setAspectRatio(1.6).setMaxWidth(200).getIMGAttributes(400, 300); + assertTrue(imgAttributes, imgAttributes.trim().equalsIgnoreCase("width=\"200\" height=\"125\"")); + } + + public void testTipImage() { + new TipImage(BASE64); + } + + @Test + public void testTipImage2() { + getTipImage(); + } + + @Test(expected = RuntimeException.class) + public void testTipImage3() { + new TipImage(BASE64WRONG); + } + + public void testTipImage4() { + TipImage tipImage = new TipImage(BASE64WRONG2); + assertTrue(tipImage.getIMGAttributes(1, 1).contains("plip")); + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipImageURLTest.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipImageURLTest.java new file mode 100644 index 000000000..c182d09fe --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipImageURLTest.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import org.eclipse.core.runtime.AssertionFailedException; +import org.junit.Test; + +public class TipImageURLTest { + + private static final String URL = "http://remainsoftware.com/img.png"; + + @Test(expected = Exception.class) + public void testTipImage() throws IOException { + new TipImage((URL) null); + } + + @Test(expected = MalformedURLException.class) + public void testTipImage3() throws IOException { + new TipImage(new URL("0gl kjfslkfjsl dkfjsldkfjl")); + } + + @Test + public void testTipImage2() throws IOException { + getTipImage(); + } + + private TipImage getTipImage() throws IOException { + return new TipImage(new URL(URL)); + } + + @Test + public void testSetMaxHeight() throws IOException { + String imgAttributes = new TipImage(new URL(URL)).setAspectRatio(2).setMaxHeight(300).getIMGAttributes(200, + 200); + assertTrue(imgAttributes, imgAttributes.trim().equalsIgnoreCase("width=\"200\" height=\"100\"")); + } + + @Test + public void testSetMaxWidth() throws IOException { + String imgAttributes = new TipImage(new URL(URL)).setAspectRatio(1.6).setMaxWidth(200).getIMGAttributes(400, + 300); + assertTrue(imgAttributes, imgAttributes.trim().equalsIgnoreCase("width=\"200\" height=\"125\"")); + + } + + @Test(expected = AssertionFailedException.class) + public void testAssertWidth() throws IOException { + new TipImage(new URL(URL)).setAspectRatio(0, 100, false); + } + + @Test(expected = AssertionFailedException.class) + public void testAssertHeight() throws IOException { + new TipImage(new URL(URL)).setAspectRatio(1000, 0, false); + } + + @Test + public void testSetAspectRatioIntIntFalse() throws IOException { + String result = getTipImage().setAspectRatio(200, 50, false).getIMGAttributes(100, 100).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"100\" height=\"25\"")); + } + + @Test + public void testSetAspectRatioIntIntTrue() throws IOException { + String result = getTipImage().setAspectRatio(400, 300, true).getIMGAttributes(740, 370).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"400\" height=\"300\"")); + } + + @Test + public void testSetAspectRatioDouble() throws IOException { + String result = getTipImage().setAspectRatio(1.5).getIMGAttributes(740, 370).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"555\" height=\"370\"")); + } + + @Test + public void testGetIMGAttributes() throws IOException { + String result = getTipImage().setAspectRatio(1.5).getIMGAttributes(740, 370).trim(); + assertTrue(result, result.equalsIgnoreCase("width=\"555\" height=\"370\"")); + } + + @Test + public void testSetExtension() throws IOException { + // assertTrue(getTipImage().getIMGAttributes(19, 10).contains("png")); + } + + @Test + public void testSetExtension2() throws IOException { + // assertTrue(getTipImage().setExtension("bmp").getBase64Image().contains("bmp")); + // assertTrue(getTipImage().getIMGAttributes(19, 10).contains("png")); + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipManagerTest.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipManagerTest.java new file mode 100644 index 000000000..f9d5c563e --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipManagerTest.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.tips.core.internal.LogUtil; +import org.junit.Before; +import org.junit.Test; + +public class TipManagerTest { + + private TestTipManager fManager; + private TestTipProvider fProvider1; + private TestTipProvider fProvider2; + + @Before + public void testTipManager() { + fManager = new TestTipManager(); + fProvider1 = new TestTipProvider(); + fProvider2 = new TestTipProvider(); + } + + @Test + public void testGetProvider() { + fManager.register(fProvider1); + TipProvider provider = fManager.getProvider(fProvider1.getID()); + assertTrue(provider == fProvider1); + } + + @Test + public void testRegister() { + fManager.register(fProvider1); + TipProvider provider = fManager.getProvider(fProvider1.getID()); + assertTrue(provider == fProvider1); + } + + /** + * Only one provider with the same id can be registered. + */ + @Test + public void testGetProviders() { + fManager.register(fProvider1); + fManager.register(fProvider2); + fManager.register(fProvider2); + assertTrue(fManager.getProviders().size() + "", fManager.getProviders().size() == 1); + } + + @Test + public void testIsRunAtStartup() { + assertTrue(fManager.isRunAtStartup()); + fManager.setRunAtStartup(false); + assertTrue(!fManager.isRunAtStartup()); + } + + @Test + public void testSetRunAtStartup() { + assertTrue(fManager.isRunAtStartup()); + fManager.setRunAtStartup(false); + assertTrue(!fManager.isRunAtStartup()); + } + + @Test + public void testLoad() { + ArrayList<String> test = new ArrayList<>(); + TestTipProvider testTipProvider = new TestTipProvider() { + @Override + public IStatus loadNewTips(IProgressMonitor monitor) { + test.add("fff"); + return Status.OK_STATUS; + } + }; + fManager.register(testTipProvider); + assertTrue(!test.isEmpty()); + } + + @Test + public void testLoad2() { + ArrayList<String> test = new ArrayList<>(); + TestTipProvider testTipProvider = new TestTipProvider() { + @Override + public IStatus loadNewTips(IProgressMonitor monitor) { + test.add("fff"); + return Status.OK_STATUS; + } + }; + fManager.register(testTipProvider); + assertTrue(!test.isEmpty()); + } + + @Test + public void testOpen() { + ArrayList<String> test = new ArrayList<>(); + TestTipManager m = new TestTipManager() { + @Override + public TipManager open(boolean startUp) { + if (startUp) { + test.add("1"); + } else { + test.add("1"); + test.add("2"); + } + return this; + } + }; + m.open(true); + assertTrue(test.size() == 1); + test.clear(); + m.open(false); + assertTrue(test.size() == 2); + } + + @Test + public void testDispose() { + fManager.dispose(); + } + + @Test + public void testDispose2() { + fManager.register(fProvider1); + fManager.dispose(); + } + + @Test + public void testLogClassOfQException() { + Exception e = new Exception("FFF"); + fManager.log(LogUtil.error(getClass(), e)); + } + + @Test + public void testIsRead() { + fManager.register(fProvider1); + fProvider1.setTips(Arrays.asList(new TestTip(fProvider1.getID(),"<b>bold</b>", "Tip 1"), + new TestTip(fProvider1.getID(),"<b>bold2</b>", "Tip 2"))); + fManager.setAsRead(fProvider1.getCurrentTip()); + assertTrue(fManager.isRead(fProvider1.getCurrentTip())); + } + + @Test + public void testSetRead() { + fManager.register(fProvider1); + fProvider1.setTips(Arrays.asList(new TestTip(fProvider1.getID(),"<b>bold</b>", "Tip 1"), + new TestTip(fProvider1.getID(),"<b>bold2</b>", "Tip 2"))); + fManager.setAsRead(fProvider1.getCurrentTip()); + assertTrue(fManager.isRead(fProvider1.getCurrentTip())); + } + + @Test + public void testSetServeUnread() { + fManager.register(fProvider1); + fProvider1.setTips(Arrays.asList(new TestTip(fProvider1.getID(),"<b>bold</b>", "Tip 1"), + new TestTip(fProvider1.getID(),"<b>bold2</b>", "Tip 2"))); + fManager.setAsRead(fProvider1.getCurrentTip()); + assertTrue(fProvider1.getTips(true).size() + "", fProvider1.getTips(true).size() == 1); + fManager.setServeReadTips(true); + assertTrue(fProvider1.getTips(true).size() == 2); + } + + @Test + public void testIsServeUnread() { + assertTrue(fManager.mustServeReadTips() == false); + fManager.setServeReadTips(true); + assertTrue(fManager.mustServeReadTips()); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipProviderTest.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipProviderTest.java new file mode 100644 index 000000000..f56013e64 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipProviderTest.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.junit.Before; +import org.junit.Test; + +public class TipProviderTest { + + private TestTipManager fManager; + private TestTipProvider fProvider; + + @Before + public void testTipProvider() { + fManager = new TestTipManager(); + fProvider = (TestTipProvider) new TestTipProvider().setManager(fManager); + } + + @Test + public void testDispose() { + fProvider.dispose(); + } + + @Test + public void testGetDescription() { + assertTrue(fProvider.getDescription() != null); + } + + @Test + public void testGetID() { + assertTrue(fProvider.getID() != null); + assertTrue(fProvider.getID().equals(fProvider.getClass().getName())); + } + + + @Test + public void testGetImage() { + assertTrue(fProvider.getImage() != null); + } + + @Test + public void testGetTips() { + assertTrue(fProvider.getTips(false).size() == 0); + createTestDate(); + fManager.setAsRead(fProvider.getNextTip()); + assertTrue(fProvider.getTips(false).size() == 2); + assertTrue(fProvider.getTips(false).size() == 2); + List<Tip> tips = fProvider.getTips(true); + assertTrue(fProvider.getTips(true).size() == 1); + ((TipManager) fProvider.getManager()).setServeReadTips(true); + assertTrue(fProvider.getTips(false).size() == 2); + } + + private void createTestDate() { + fProvider.setTips(Arrays.asList(new TestTip(fProvider.getID(),"<b>bold</b>", "Tip 1"), + new TestTip(fProvider.getID(),"<b>bold2</b>", "Tip 2"))); + } + + @Test + public void testGetCurrentTip() { + assertTrue(fProvider.getNextTip().equals(fProvider.getCurrentTip())); + } + + @Test + public void testGetCurrentTip2() { + assertTrue(fProvider.getCurrentTip().equals(fProvider.getPreviousTip())); + } + + @Test + public void testGetNextTip() { + createTestDate(); + fManager.setAsRead(fProvider.getNextTip()); + assertTrue(fProvider.getNextTip().equals(fProvider.getCurrentTip())); + Tip nextTip = fProvider.getNextTip(); + fManager.setAsRead(nextTip); + assertTrue(fManager.isRead(nextTip)); + Tip nextTip2 = fProvider.getNextTip(); + fManager.setAsRead(nextTip2); + assertTrue(fManager.isRead(nextTip2)); + assertTrue(fProvider.getNextTip().getClass().getSimpleName().equals("FinalTip")); + ((TipManager) fProvider.getManager()).setServeReadTips(true); + assertFalse(fProvider.getNextTip().getClass().getSimpleName().equals("FinalTip")); + } + + @Test + public void testGetPreviousTip() { + assertTrue(fProvider.getPreviousTip().equals(fProvider.getCurrentTip())); + assertTrue(fProvider.getPreviousTip().equals(fProvider.getCurrentTip())); + } + + @Test + public void testGetPreviousTip2() { + assertTrue(!fProvider.getPreviousTip().equals(null)); + assertTrue(fProvider.getNextTip().getClass().getSimpleName().equals("FinalTip")); + } + + @Test + public void testGetPreviousTip3() { + ((TipManager) fProvider.getManager()).setServeReadTips(true); + assertTrue(fProvider.getPreviousTip().equals(fProvider.getCurrentTip())); + } + + @Test + public void testGetPreviousTip4() { + createTestDate(); + assertTrue(fProvider.getPreviousTip() != null); + assertTrue(fProvider.getPreviousTip() != null); + assertTrue(fProvider.getPreviousTip() != null); + } + + @Test + public void testGetTipManager() { + assertTrue(fProvider.getManager().equals(fManager)); + } + + @Test + public void testIsReady() { + TestTipProvider p = (TestTipProvider) new TestTipProvider().setManager(fManager); + assertTrue(!p.isReady()); + p.setTips(Collections.emptyList()); + assertTrue(p.isReady()); + } + + @Test + public void testLoad() { + TestTipProvider p = (TestTipProvider) new TestTipProvider().setManager(fManager); + assertTrue(!p.isReady()); + p.loadNewTips(new NullProgressMonitor()); + assertTrue(p.isReady()); + } + + @Test + public void testSetManager() { + TestTipProvider p = new TestTipProvider(); + assertTrue(p.getManager() == null); + p.setManager(fManager); + assertTrue(p.getManager() != null); + } + + @Test + public void testSetTips() { + TestTipProvider p = new TestTipProvider() { + @Override + public IStatus loadNewTips(IProgressMonitor pMonitor) { + assertTrue(getTips(false).size() == 0); + assertTrue(setTips(Arrays.asList(new Tip[] { new TestTip(getID(),"DDD", "XXX") })).getTips(false) + .size() == 1); + return Status.OK_STATUS; + } + }; + assertTrue(p.getTips(false).size() == 0); + fManager.register(p); + assertTrue(p.getTips(false).size() == 1); + } + + @Test + public void testAddTips() { + TestTipProvider p = new TestTipProvider() { + @Override + public IStatus loadNewTips(IProgressMonitor pMonitor) { + assertTrue(getTips(false).size() == 0); + assertTrue(setTips(Arrays.asList(new Tip[] { new TestTip(getID(),"DDD", "XXX") })).getTips(false) + .size() == 1); + assertTrue(addTips(Arrays.asList(new Tip[] { new TestTip(getID(),"DDD", "XXX") })).getTips(false) + .size() == 2); + return Status.OK_STATUS; + } + }; + fManager.register(p); + + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipTest.java b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipTest.java new file mode 100644 index 000000000..81e4a09e9 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/core/TipTest.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.core; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +public class TipTest { + + private static final String HTML = "<head></head>"; + private static final String SUBJECT_TIP = "Tip Subject"; + private TestTipManager fManager; + private TestTipProvider fProvider; + private TestTip fTip; + + @Before + public void setup() { + fManager = new TestTipManager(); + fProvider = (TestTipProvider) new TestTipProvider().setManager(fManager); + createTestDate(); + fTip = new TestTip(fProvider.getID(), HTML, SUBJECT_TIP) { + @Override + public List<TipAction> getActions() { + ArrayList<TipAction> actions = new ArrayList<>(); + ArrayList<String> result = new ArrayList<>(); + Runnable runner = () -> result.add("entry"); + + actions.add(new TipAction("text", "tooltip", runner, null)); + return actions; + } + }; + } + + @Test + public void testHashCode() { + assertTrue(fProvider.getNextTip().hashCode() != 0); + } + + @Test + public void testHashCode2() { + TestTip testTip = new TestTip(fProvider.getID(), HTML, SUBJECT_TIP); + TestTip testTip2 = new TestTip(fProvider.getID(), HTML, SUBJECT_TIP); + assertTrue(testTip.hashCode() == testTip2.hashCode()); + } + + @Test + public void testTip() { + new TestTip(fProvider.getID(),HTML, SUBJECT_TIP); + } + + @Test + public void testGetAction() { + assertTrue(fTip.getActions().size() > 0); + } + + @Test + public void testGetCreationDate() { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(fTip.getCreationDate()); + assertTrue(calendar.get(Calendar.MONTH) == 11); + assertTrue(calendar.get(Calendar.YEAR) == 1964); + assertTrue(calendar.get(Calendar.DAY_OF_MONTH) == 31); + } + + @Test + public void testGetHTML() { + assertTrue(fTip.getHTML() != null); + } + + @Test + public void testGetImage() { + assertTrue(fTip.getImage() == null); + } + + @Test + public void testGetSubject() { + assertTrue(fTip.getSubject() != null); + assertTrue(fTip.getSubject().equals(SUBJECT_TIP)); + } + + @Test + public void testEqualsObject() { + TestTip testTip = new TestTip(fProvider.getID(),HTML, SUBJECT_TIP); + TestTip testTipx = new TestTip(fProvider.getID(),HTML, SUBJECT_TIP); + assertTrue(!testTip.equals("hello")); + assertTrue(!testTip.equals(null)); + assertTrue(testTip.equals(testTip)); + assertTrue(!testTip.equals(fTip)); + assertTrue(testTip.equals(testTipx)); + + TestTipProvider testTipProvider = new TestTipProvider() { + @Override + public String getID() { + return "sss"; + } + }; + TestTip testTip2 = new TestTip(fProvider.getID(),HTML, SUBJECT_TIP + "DDD"); + assertTrue(!testTip.equals(testTip2)); + assertTrue(!testTip.equals(testTip2)); + + TestTip testTip3 = new TestTip(fProvider.getID(),HTML, SUBJECT_TIP + "DDD"); + assertTrue(!testTip.equals(testTip3)); + assertTrue(!testTip3.equals(testTip)); + + TestTipProvider testTipProvider2 = new TestTipProvider() { + @Override + public String getID() { + return null; + } + }; + + TestTip testTip4 = new TestTip(fProvider.getID(), HTML, SUBJECT_TIP + "DDD"); + assertTrue(!testTip.equals(testTip4)); + assertTrue(!testTip4.equals(testTip)); + + TestTip testTip5 = new TestTip(fProvider.getID(),HTML, SUBJECT_TIP + "DDDWW"); + assertTrue(!testTip.equals(testTip5)); + assertTrue(!testTip5.equals(testTip)); + + TestTip testTip6 = new TestTip(fProvider.getID(),HTML, null); + assertTrue(!testTip.equals(testTip6)); + assertTrue(!testTip6.equals(testTip)); + + } + + @Test + public void testIsRead() { + assertTrue(!fManager.isRead(fTip)); + fManager.setAsRead(fTip); + fManager.setAsRead(fTip); + assertTrue(fManager.isRead(fTip)); + } + + private void createTestDate() { + fProvider.setTips(Arrays.asList(new TestTip(fProvider.getID(),"<b>bold</b>", "Tip 1"), + new TestTip(fProvider.getID(),"<b>bold2</b>", "Tip 2"))); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/Sleak.java b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/Sleak.java new file mode 100644 index 000000000..88d1856d8 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/Sleak.java @@ -0,0 +1,306 @@ +package org.eclipse.tips.manual.tests; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +/* + * Copyright (c) 2000, 2018 IBM Corp. All rights reserved. + * This file is made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + */ +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.DeviceData; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +public class Sleak { + Display display; + Shell shell; + List list; + Canvas canvas; + Button start, stop, check; + Text text; + Label label; + + Object[] oldObjects = new Object[0]; + Error[] oldErrors = new Error[0]; + Object[] objects = new Object[0]; + Error[] errors = new Error[0]; + + public void open() { + display = Display.getCurrent(); + shell = new Shell(display); + shell.setText("S-Leak"); + list = new List(shell, SWT.BORDER | SWT.V_SCROLL); + list.addListener(SWT.Selection, event -> refreshObject()); + text = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); + canvas = new Canvas(shell, SWT.BORDER); + canvas.addListener(SWT.Paint, event -> paintCanvas(event)); + check = new Button(shell, SWT.CHECK); + check.setText("Stack"); + check.addListener(SWT.Selection, e -> toggleStackTrace()); + start = new Button(shell, SWT.PUSH); + start.setText("Snap"); + start.addListener(SWT.Selection, event -> refreshAll()); + stop = new Button(shell, SWT.PUSH); + stop.setText("Diff"); + stop.addListener(SWT.Selection, event -> refreshDifference()); + label = new Label(shell, SWT.BORDER); + label.setText("0 object(s)"); + shell.addListener(SWT.Resize, e -> layout()); + check.setSelection(false); + text.setVisible(false); + Point size = shell.getSize(); + shell.setSize(size.x / 2, size.y / 2); + shell.open(); + refreshAll(); + } + + void refreshLabel() { + int colors = 0, cursors = 0, fonts = 0, gcs = 0, images = 0; + for (Object object : objects) { + if (object instanceof Color) { + colors++; + } + if (object instanceof Cursor) { + cursors++; + } + if (object instanceof Font) { + fonts++; + } + if (object instanceof GC) { + gcs++; + } + if (object instanceof Image) { + images++; + } + } + String string = ""; + if (colors != 0) { + string += colors + " Color(s)\n"; + } + if (cursors != 0) { + string += cursors + " Cursor(s)\n"; + } + if (fonts != 0) { + string += fonts + " Font(s)\n"; + } + if (gcs != 0) { + string += gcs + " GC(s)\n"; + } + if (images != 0) { + string += images + " Image(s)\n"; + } + /* Currently regions are not counted. */ + // if (regions != 0) string += regions + " Region(s)\n"; + if (string.length() != 0) { + string = string.substring(0, string.length() - 1); + } + label.setText(string); + } + + void refreshDifference() { + DeviceData info = display.getDeviceData(); + if (!info.tracking) { + MessageBox dialog = new MessageBox(shell, SWT.ICON_WARNING | SWT.OK); + dialog.setText(shell.getText()); + dialog.setMessage("Warning: Device is not tracking resource allocation"); + dialog.open(); + } + Object[] newObjects = info.objects; + Error[] newErrors = info.errors; + Object[] diffObjects = new Object[newObjects.length]; + Error[] diffErrors = new Error[newErrors.length]; + int count = 0; + for (int i = 0; i < newObjects.length; i++) { + int index = 0; + while (index < oldObjects.length) { + if (newObjects[i] == oldObjects[index]) { + break; + } + index++; + } + if (index == oldObjects.length) { + diffObjects[count] = newObjects[i]; + diffErrors[count] = newErrors[i]; + count++; + } + } + objects = new Object[count]; + errors = new Error[count]; + System.arraycopy(diffObjects, 0, objects, 0, count); + System.arraycopy(diffErrors, 0, errors, 0, count); + list.removeAll(); + text.setText(""); + canvas.redraw(); + for (Object object : objects) { + list.add(objectName(object)); + } + refreshLabel(); + layout(); + } + + String objectName(Object object) { + String string = object.toString(); + int index = string.lastIndexOf('.'); + if (index == -1) { + return string; + } + return string.substring(index + 1, string.length()); + } + + void toggleStackTrace() { + refreshObject(); + layout(); + } + + void paintCanvas(Event event) { + canvas.setCursor(null); + int index = list.getSelectionIndex(); + if (index == -1) { + return; + } + GC gc = event.gc; + Object object = objects[index]; + if (object instanceof Color) { + if (((Color) object).isDisposed()) { + return; + } + gc.setBackground((Color) object); + gc.fillRectangle(canvas.getClientArea()); + return; + } + if (object instanceof Cursor) { + if (((Cursor) object).isDisposed()) { + return; + } + canvas.setCursor((Cursor) object); + return; + } + if (object instanceof Font) { + if (((Font) object).isDisposed()) { + return; + } + gc.setFont((Font) object); + FontData[] array = gc.getFont().getFontData(); + String string = ""; + String lf = text.getLineDelimiter(); + for (FontData data : array) { + String style = "NORMAL"; + int bits = data.getStyle(); + if (bits != 0) { + if ((bits & SWT.BOLD) != 0) { + style = "BOLD "; + } + if ((bits & SWT.ITALIC) != 0) { + style += "ITALIC"; + } + } + string += data.getName() + " " + data.getHeight() + " " + style + lf; + } + gc.drawString(string, 0, 0); + return; + } + // NOTHING TO DRAW FOR GC + // if (object instanceof GC) { + // return; + // } + if (object instanceof Image) { + if (((Image) object).isDisposed()) { + return; + } + gc.drawImage((Image) object, 0, 0); + return; + } + if (object instanceof Region) { + if (((Region) object).isDisposed()) { + return; + } + String string = ((Region) object).getBounds().toString(); + gc.drawString(string, 0, 0); + return; + } + } + + void refreshObject() { + int index = list.getSelectionIndex(); + if (index == -1) { + return; + } + if (check.getSelection()) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + PrintStream s = new PrintStream(stream); + errors[index].printStackTrace(s); + text.setText(stream.toString()); + text.setVisible(true); + canvas.setVisible(false); + } else { + canvas.setVisible(true); + text.setVisible(false); + canvas.redraw(); + } + } + + void refreshAll() { + oldObjects = new Object[0]; + oldErrors = new Error[0]; + refreshDifference(); + oldObjects = objects; + oldErrors = errors; + } + + void layout() { + Rectangle rect = shell.getClientArea(); + int width = 0; + String[] items = list.getItems(); + GC gc = new GC(list); + for (int i = 0; i < objects.length; i++) { + width = Math.max(width, gc.stringExtent(items[i]).x); + } + gc.dispose(); + Point size1 = start.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Point size2 = stop.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Point size3 = check.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Point size4 = label.computeSize(SWT.DEFAULT, SWT.DEFAULT); + width = Math.max(size1.x, Math.max(size2.x, Math.max(size3.x, width))); + width = Math.max(64, Math.max(size4.x, list.computeSize(width, SWT.DEFAULT).x)); + start.setBounds(0, 0, width, size1.y); + stop.setBounds(0, size1.y, width, size2.y); + check.setBounds(0, size1.y + size2.y, width, size3.y); + label.setBounds(0, rect.height - size4.y, width, size4.y); + int height = size1.y + size2.y + size3.y; + list.setBounds(0, height, width, rect.height - height - size4.y); + text.setBounds(width, 0, rect.width - width, rect.height); + canvas.setBounds(width, 0, rect.width - width, rect.height); + } + + public static void main(String[] args) { + Display display = new Display(); + Sleak sleak = new Sleak(); + sleak.open(); + while (!sleak.shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + display.dispose(); + } + +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/SleakTipManager.java b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/SleakTipManager.java new file mode 100644 index 000000000..150ba8021 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/SleakTipManager.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.manual.tests; + +import java.net.MalformedURLException; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.swt.graphics.DeviceData; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tips.core.ITipManager; +import org.eclipse.tips.core.JsonTestProvider; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipManager; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.ui.internal.TipDialog; +import org.eclipse.tips.ui.internal.util.ResourceManager; + +/** + * Class to manage the tip providers and start the tip of the day UI. + */ +public class SleakTipManager extends TipManager { + + private static SleakTipManager instance = new SleakTipManager(); + + public static void main(String[] args) throws MalformedURLException { + instance.register(new JsonTestProvider()); + if (!instance.getProviders().isEmpty()) { + instance.open(true); + } + } + + /** + * @return the tip manager instance. + */ + public static SleakTipManager getInstance() { + return instance; + } + + private SleakTipManager() { + } + + /** + * For resource leak detection rename this method to open and run the IDE. Won't + * work on Linux because GTK cannot handle multiple displays. + */ + @Override + public TipManager open(boolean pStart) { + + Thread t = new Thread(() -> { + + DeviceData data = new DeviceData(); + data.tracking = true; + Display display = new Display(data); + Shell shell = new Shell(display); + shell.setLayout(new FillLayout()); + new Sleak().open(); + TipDialog tipDialog = new TipDialog(shell, SleakTipManager.this, TipDialog.DEFAULT_STYLE); + tipDialog.addDisposeListener(pE -> dispose()); + tipDialog.open(); + shell.pack(); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + display.dispose(); + }); + + t.start(); + return this; + + } + + @Override + public ITipManager register(TipProvider provider) { + super.register(provider); + load(provider); + return this; + } + + private void load(TipProvider pProvider) { + pProvider.loadNewTips(new NullProgressMonitor()); + } + + @Override + public boolean isRead(Tip pTip) { + return false; + } + + @Override + public TipManager setAsRead(Tip pTip) { + return this; + } + + protected synchronized SleakTipManager setNewTips(boolean pNewTips) { + return this; + } + + @Override + public void dispose() { + ResourceManager.dispose(); + super.dispose(); + } + + @Override + public TipManager setRunAtStartup(boolean pShouldRun) { + return this; + } + + @Override + public ITipManager log(IStatus pStatus) { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getPriority(TipProvider pProvider) { + return 0; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/XML.java b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/XML.java new file mode 100644 index 000000000..888bbe11d --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/XML.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.manual.tests; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +public class XML { + + public static void main(String[] args) + throws ParserConfigurationException, TransformerException, SAXException, IOException { + String pExpression = "<with variable=\"activeWorkbenchWindow.activePerspective\"><equals value=\"org.eclipse.jdt.ui.JavaPerspective\"></equals></with>"; + pExpression = "<enablement>" + pExpression + "</enablement>"; + pExpression = "<?xml version=\"1.0\"?>" + pExpression; + System.out.println(pExpression); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + Document doc = factory.newDocumentBuilder().parse(new ByteArrayInputStream(pExpression.getBytes())); + Element element2 = (Element) doc.getElementsByTagName("enablement").item(0); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + DOMSource source = new DOMSource(element2); + StreamResult result = new StreamResult(System.out); + transformer.transform(source, result); + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/package-info.java b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/package-info.java new file mode 100644 index 000000000..9e3779299 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/manual/tests/package-info.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * + */ +/** + * @author jongw + * + */ +package org.eclipse.tips.manual.tests;
\ No newline at end of file diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/tests/Good.java b/org.eclipse.tips.tests/src/org/eclipse/tips/tests/Good.java new file mode 100644 index 000000000..7232dd419 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/tests/Good.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class Good { + + @Test + public void test() { + assertTrue(true); + } +} diff --git a/org.eclipse.tips.tests/src/org/eclipse/tips/util/ImageUtilTest.java b/org.eclipse.tips.tests/src/org/eclipse/tips/util/ImageUtilTest.java new file mode 100644 index 000000000..d98699d89 --- /dev/null +++ b/org.eclipse.tips.tests/src/org/eclipse/tips/util/ImageUtilTest.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.util; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tips.ui.internal.util.ImageUtil; +import org.junit.Test; + +public class ImageUtilTest { + + private static String fImageBase64 = "" // + + "iVBORw0KGgoAAAANSUhEUgAAACIAAAAkCAYAAADsHujfAAAAAXNSR0IArs4c6QAAAARnQU1BAACx" + + "jwv8YQUAAAAJcEhZcwAAJOgAACToAYJjBRwAAAEcSURBVFhH7dZBCsIwEIXh3MkbuPJubtwI0kOIK" + + "IJuddseo+eIPORBDZM0MyPaRQr/IiRtP9osEoa+j0uoQdKykPVtiLunPKdtcx/i9iHPMRECRDi+82K" + + "A4LNKGBHCG5kVM0UgjKV1SITgxdMHIC1Gg0DZPeLBaBEoC0EWjAWBihCkwVgRaBaCajAeBKqCoBLGi0" + + "DVECRhVtfPsQWBVBAkYZgVgdQQlPsy0traTJB0TzDuGUtqSA7BrBgVJEVgLP0mC6YaIiE49w1MFaSEYF" + + "7MLKQGwTyYIkSDYFZMFmJBMAtGhHgQTIsRIdObLQiWYnAWltYhEYJDrhfBiCkhUHGz/rIGSWuQtAZJC+M" + + "4xn93Ol9iiAu49oduKZAuvgC5R8NSTiN3qAAAAABJRU5ErkJggg=="; + + private static String fImageBase64HTML = "data:image/png;base64," // + + "iVBORw0KGgoAAAANSUhEUgAAACIAAAAkCAYAAADsHujfAAAAAXNSR0IArs4c6QAAAARnQU1BAACx" + + "jwv8YQUAAAAJcEhZcwAAJOgAACToAYJjBRwAAAEcSURBVFhH7dZBCsIwEIXh3MkbuPJubtwI0kOIK" + + "IJuddseo+eIPORBDZM0MyPaRQr/IiRtP9osEoa+j0uoQdKykPVtiLunPKdtcx/i9iHPMRECRDi+82K" + + "A4LNKGBHCG5kVM0UgjKV1SITgxdMHIC1Gg0DZPeLBaBEoC0EWjAWBihCkwVgRaBaCajAeBKqCoBLGi0" + + "DVECRhVtfPsQWBVBAkYZgVgdQQlPsy0traTJB0TzDuGUtqSA7BrBgVJEVgLP0mC6YaIiE49w1MFaSEYF" + + "7MLKQGwTyYIkSDYFZMFmJBMAtGhHgQTIsRIdObLQiWYnAWltYhEYJDrhfBiCkhUHGz/rIGSWuQtAZJC+M" + + "4xn93Ol9iiAu49oduKZAuvgC5R8NSTiN3qAAAAABJRU5ErkJggg=="; + + @Test + public void decodeImageToBase64Test() throws IOException { + Image image = new Image(null, ImageUtil.decodeToImage(fImageBase64)); + String base64Image = ImageUtil.decodeFromImage(image, SWT.IMAGE_PNG); + image.dispose(); + image = new Image(null, ImageUtil.decodeToImage(base64Image)); + String base64Image2 = ImageUtil.decodeFromImage(image, SWT.IMAGE_PNG); + assertTrue(base64Image, base64Image.equals(base64Image2)); + image.dispose(); + + Image image2 = new Image(null, ImageUtil.decodeToImage(fImageBase64HTML)); + String base64Image3 = ImageUtil.decodeFromImage(image2, SWT.IMAGE_PNG); + image2.dispose(); + image2 = new Image(null, ImageUtil.decodeToImage(base64Image3)); + String base64Image4 = ImageUtil.decodeFromImage(image2, SWT.IMAGE_PNG); + assertTrue(base64Image3, base64Image3.equals(base64Image4)); + image2.dispose(); + } + + @Test + public void testGetWidth() { + assertTrue(ImageUtil.getWidth(1, 1000, 100) == 100); + assertTrue(ImageUtil.getWidth(1, 100, 1000) == 100); + assertTrue(ImageUtil.getWidth(1, 100, 99) == 99); + assertTrue(ImageUtil.getWidth(1, 100, 98) == 98); + assertTrue(ImageUtil.getWidth(1, 100, 100) == 100); + assertTrue(ImageUtil.getWidth(1, 99, 100) == 99); + assertTrue(ImageUtil.getWidth(1, 77, 77) == 77); + assertTrue(ImageUtil.getWidth(1, 101, 100) == 100); + assertTrue(ImageUtil.getWidth(1, 149, 100) == 100); + assertTrue(ImageUtil.getWidth(1, 200, 300) == 200); + assertTrue(ImageUtil.getWidth(1, 11, 10) == 10); + + assertTrue(ImageUtil.getWidth(0.5, 1000, 100) == 50); + assertTrue(ImageUtil.getWidth(0.5, 100, 1000) == 100); + assertTrue(ImageUtil.getWidth(0.5, 100, 99) == 49); + assertTrue(ImageUtil.getWidth(0.5, 100, 98) == 49); + assertTrue(ImageUtil.getWidth(0.5, 100, 100) == 50); + assertTrue(ImageUtil.getWidth(0.5, 99, 100) == 50); + assertTrue(ImageUtil.getWidth(0.5, 77, 77) == 38); + assertTrue(ImageUtil.getWidth(0.5, 101, 100) == 50); + assertTrue(ImageUtil.getWidth(0.5, 149, 100) == 50); + assertTrue(ImageUtil.getWidth(0.5, 200, 300) == 150); + assertTrue(ImageUtil.getWidth(0.5, 11, 10) == 5); + + assertTrue(ImageUtil.getWidth(2, 1000, 100) == 200); + assertTrue(ImageUtil.getWidth(2, 100, 1000) == 100); + assertTrue(ImageUtil.getWidth(2, 100, 99) == 100); + assertTrue(ImageUtil.getWidth(2, 100, 50) == 100); + assertTrue(ImageUtil.getWidth(2, 100, 49) == 98); + assertTrue(ImageUtil.getWidth(2, 100, 98) == 100); + assertTrue(ImageUtil.getWidth(2, 100, 100) == 100); + assertTrue(ImageUtil.getWidth(2, 99, 100) == 99); + assertTrue(ImageUtil.getWidth(2, 77, 77) == 77); + assertTrue(ImageUtil.getWidth(2, 101, 100) == 101); + assertTrue(ImageUtil.getWidth(2, 149, 100) == 149); + assertTrue(ImageUtil.getWidth(2, 200, 300) == 200); + assertTrue(ImageUtil.getWidth(2, 11, 10) == 11); + } + + @Test + public void testGetHeight() { + assertTrue(ImageUtil.getHeight(1, 1000, 100) == 100); + assertTrue(ImageUtil.getHeight(1, 100, 1000) == 100); + assertTrue(ImageUtil.getHeight(1, 100, 99) == 99); + assertTrue(ImageUtil.getHeight(1, 100, 98) == 98); + assertTrue(ImageUtil.getHeight(1, 100, 100) == 100); + assertTrue(ImageUtil.getHeight(1, 99, 100) == 99); + assertTrue(ImageUtil.getHeight(1, 77, 77) == 77); + assertTrue(ImageUtil.getHeight(1, 101, 100) == 100); + assertTrue(ImageUtil.getHeight(1, 149, 100) == 100); + assertTrue(ImageUtil.getHeight(1, 200, 300) == 200); + assertTrue(ImageUtil.getHeight(1, 11, 10) == 10); + + assertTrue(ImageUtil.getHeight(0.5, 1000, 100) == 100); + assertTrue(ImageUtil.getHeight(0.5, 100, 1000) == 200); + assertTrue(ImageUtil.getHeight(0.5, 100, 99) == 99); + assertTrue(ImageUtil.getHeight(0.5, 100, 98) == 98); + assertTrue(ImageUtil.getHeight(0.5, 100, 100) == 100); + assertTrue(ImageUtil.getHeight(0.5, 99, 100) == 100); + assertTrue(ImageUtil.getHeight(0.5, 77, 77) == 77); + assertTrue(ImageUtil.getHeight(0.5, 101, 100) == 100); + assertTrue(ImageUtil.getHeight(0.5, 149, 100) == 100); + assertTrue(ImageUtil.getHeight(0.5, 200, 300) == 300); + assertTrue(ImageUtil.getHeight(0.5, 11, 10) == 10); + + assertTrue(ImageUtil.getHeight(2, 1000, 100) == 100); + assertTrue(ImageUtil.getHeight(2, 100, 1000) == 50); + assertTrue(ImageUtil.getHeight(2, 100, 99) == 50); + assertTrue(ImageUtil.getHeight(2, 100, 50) == 50); + assertTrue(ImageUtil.getHeight(2, 100, 49) == 49); + assertTrue(ImageUtil.getHeight(2, 100, 98) == 50); + assertTrue(ImageUtil.getHeight(2, 100, 100) == 50); + assertTrue(ImageUtil.getHeight(2, 99, 100) == 49); + assertTrue(ImageUtil.getHeight(2, 77, 77) == 38); + assertTrue(ImageUtil.getHeight(2, 101, 100) == 50); + assertTrue(ImageUtil.getHeight(2, 149, 100) == 74); + assertTrue(ImageUtil.getHeight(2, 200, 300) == 100); + assertTrue(ImageUtil.getHeight(2, 11, 10) == 5); + } +} diff --git a/org.eclipse.tips.ui/.classpath b/org.eclipse.tips.ui/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/org.eclipse.tips.ui/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.tips.ui/.gitignore b/org.eclipse.tips.ui/.gitignore new file mode 100644 index 000000000..0f630157f --- /dev/null +++ b/org.eclipse.tips.ui/.gitignore @@ -0,0 +1,2 @@ +/target/ +/bin/ diff --git a/org.eclipse.tips.ui/.project b/org.eclipse.tips.ui/.project new file mode 100644 index 000000000..c758a1381 --- /dev/null +++ b/org.eclipse.tips.ui/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.tips.ui</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.tips.ui/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tips.ui/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/org.eclipse.tips.ui/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.eclipse.tips.ui/META-INF/MANIFEST.MF b/org.eclipse.tips.ui/META-INF/MANIFEST.MF new file mode 100644 index 000000000..72e9b2379 --- /dev/null +++ b/org.eclipse.tips.ui/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tip of the Day UI +Bundle-SymbolicName: org.eclipse.tips.ui;singleton:=true +Bundle-Version: 0.1.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.core.runtime;bundle-version="3.13.0", + org.eclipse.jface;bundle-version="3.13.1", + org.eclipse.tips.core;bundle-version="0.1.0" +Export-Package: org.eclipse.tips.ui, + org.eclipse.tips.ui.internal, + org.eclipse.tips.ui.internal.util +Automatic-Module-Name: org.eclipse.tips.ui diff --git a/org.eclipse.tips.ui/build.properties b/org.eclipse.tips.ui/build.properties new file mode 100644 index 000000000..da4f2d034 --- /dev/null +++ b/org.eclipse.tips.ui/build.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2018 Remain Software +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# wim.jongman@remainsoftware.com - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + icons/ diff --git a/org.eclipse.tips.ui/icons/48/aleft.png b/org.eclipse.tips.ui/icons/48/aleft.png Binary files differnew file mode 100644 index 000000000..dee58a177 --- /dev/null +++ b/org.eclipse.tips.ui/icons/48/aleft.png diff --git a/org.eclipse.tips.ui/icons/48/aright.png b/org.eclipse.tips.ui/icons/48/aright.png Binary files differnew file mode 100644 index 000000000..0954a79ba --- /dev/null +++ b/org.eclipse.tips.ui/icons/48/aright.png diff --git a/org.eclipse.tips.ui/icons/64/aleft.png b/org.eclipse.tips.ui/icons/64/aleft.png Binary files differnew file mode 100644 index 000000000..0ef5cdfd3 --- /dev/null +++ b/org.eclipse.tips.ui/icons/64/aleft.png diff --git a/org.eclipse.tips.ui/icons/64/aright.png b/org.eclipse.tips.ui/icons/64/aright.png Binary files differnew file mode 100644 index 000000000..c7791cd9b --- /dev/null +++ b/org.eclipse.tips.ui/icons/64/aright.png diff --git a/org.eclipse.tips.ui/icons/lightbulb.png b/org.eclipse.tips.ui/icons/lightbulb.png Binary files differnew file mode 100644 index 000000000..d22fde8ba --- /dev/null +++ b/org.eclipse.tips.ui/icons/lightbulb.png diff --git a/org.eclipse.tips.ui/icons/popup_menu.gif b/org.eclipse.tips.ui/icons/popup_menu.gif Binary files differnew file mode 100644 index 000000000..bd37eb50b --- /dev/null +++ b/org.eclipse.tips.ui/icons/popup_menu.gif diff --git a/org.eclipse.tips.ui/pom.xml b/org.eclipse.tips.ui/pom.xml new file mode 100644 index 000000000..c0c1b7126 --- /dev/null +++ b/org.eclipse.tips.ui/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2018 Remain Software + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + wim.jongman@remainsoftware.com - initial API and implementation + --> + +<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>eclipse.platform.ua</groupId> + <artifactId>eclipse.platform.ua</artifactId> + <version>4.8.0-SNAPSHOT</version> + </parent> + <groupId>org.eclipse.ui</groupId> + <artifactId>org.eclipse.tips.ui</artifactId> + <version>0.1.0-SNAPSHOT</version> + <packaging>eclipse-plugin</packaging> +</project> diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/DefaultTipManager.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/DefaultTipManager.java new file mode 100644 index 000000000..f32d420b0 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/DefaultTipManager.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tips.core.TipManager; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.ui.internal.TipDialog; + +/** + * Class to manage the tip providers and start the tip of the day UI. + * + */ +@SuppressWarnings("restriction") +public abstract class DefaultTipManager extends TipManager { + + private TipDialog fTipDialog; + + /** + * Opens the Tip of the Day dialog. Subclasses may override if they want to + * present the Tips in a different way, e.g. in a view. + * + * @param startUp + * When called from a startup situation, true must be passed for + * <code>pStartup</code>. If in a manual starting situation, false + * must be passed. This enables the manager to decide to skip opening + * the dialog at startup (e.g., no new tip items). + * + * @see #isOpen() + */ + @Override + public TipManager open(boolean startUp) { + if (fOpen && (fTipDialog == null || fTipDialog.isDisposed())) { + fOpen = false; + } + try { + Assert.isTrue(!fOpen, "Tip of the Day already open."); + } catch (Exception e) { + log(LogUtil.error(getClass(), e)); + throw e; + } + + if (!mustOpen(startUp)) { + return this; + } + + fTipDialog = new TipDialog(Display.getCurrent().getActiveShell(), this, TipDialog.DEFAULT_STYLE); + fTipDialog.addDisposeListener(pE -> { + try { + dispose(); + } finally { + fOpen = false; + } + }); + fTipDialog.open(); + fOpen = true; + return this; + } + + // Open if not a startup call or if there are unread tips. + private boolean mustOpen(boolean startUp) { + if (!startUp) { + return true; + } + if (startUp && isRunAtStartup()) { + for (TipProvider provider : getProviders()) { + if (provider.isReady() && !provider.getTips(true).isEmpty()) { + return true; + } + } + } + return false; + } + +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/ISwtTip.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/ISwtTip.java new file mode 100644 index 000000000..46424fc4c --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/ISwtTip.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tips.core.Tip; + +/** + * A decoration of {@link Tip} class that provides the opportunity to + * create a rich SWT UI. + * + */ +public interface ISwtTip { + + /** + * Creates the top level control for this tip on the given parent composite. You + * can implement this method to build your the UI for your Tip in SWT. You can + * find and example implementation in the tips example bundle. + * + * @param parent + * the parent composite + */ + public abstract void createControl(Composite parent); +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/ProviderSelectionListener.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/ProviderSelectionListener.java new file mode 100644 index 000000000..4e0d58e92 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/ProviderSelectionListener.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal; + +import org.eclipse.swt.widgets.Slider; +import org.eclipse.tips.core.TipProvider; + +/** + * Interface for TipProvider listeners. + */ +@FunctionalInterface +public interface ProviderSelectionListener { + + /** + * Is called when the provider is selected in the {@link Slider}. + * + * @param provider + * the {@link TipProvider} that was selected + */ + public void selected(TipProvider provider); +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/Slider.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/Slider.java new file mode 100644 index 000000000..02f8fdb8b --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/Slider.java @@ -0,0 +1,406 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipManager; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.TipProviderListener; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.ui.internal.util.ImageUtil; +import org.eclipse.tips.ui.internal.util.ResourceManager; +import org.eclipse.tips.ui.internal.util.SWTResourceManager; + +@SuppressWarnings("restriction") +public class Slider extends Composite { + + private Composite fScroller; + private TipProvider fSelectedProvider; + private int fSpacing = 5; + private int fSliderIndex = 0; + private List<ProviderSelectionListener> fListeners = new ArrayList<>(); + private TipManager fTipManager; + private Button fLeftButton; + private Button fRightButton; + private TipProviderListener fProviderListener; + private Composite fSelectedProviderButton; + private HashMap<String, Image> fProviderImageCache = new HashMap<>(); + private int fIconSize = 48; + + /** + * Constructor for the Slider widget. + * + * @param parent + * the parent + * @param style + * the SWT style bits + */ + public Slider(Composite parent, int style) { + super(parent, style); + + GridLayout layout = new GridLayout(3, false); + layout.marginHeight = 0; + setLayout(layout); + + fLeftButton = new Button(this, SWT.FLAT); + GridData gd_leftButton = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); + gd_leftButton.widthHint = fIconSize / 2 + 8; + gd_leftButton.heightHint = fIconSize; + fLeftButton.setLayoutData(gd_leftButton); + fLeftButton.setImage(getImage("icons/" + fIconSize + "/aleft.png")); + fLeftButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + scrollLeft(); + } + }); + + fScroller = new Composite(this, SWT.DOUBLE_BUFFERED); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); + layoutData.heightHint = fIconSize + 4; + fScroller.setLayoutData(layoutData); + + fRightButton = new Button(this, SWT.FLAT); + GridData gd_rightButton = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); + gd_rightButton.widthHint = fIconSize / 2 + 8; + gd_rightButton.heightHint = fIconSize; + fRightButton.setLayoutData(gd_rightButton); + fRightButton.setImage(getImage("icons/" + fIconSize + "/aright.png")); + fRightButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + scrollRight(); + } + }); + + setupDisposeListener(); + setupProviderListener(); + } + + private void setupDisposeListener() { + addListener(SWT.Dispose, event -> { + fTipManager.getListenerManager().removeProviderListener(fProviderListener); + fProviderImageCache.values().forEach(img -> { + if (!img.isDisposed()) { + img.dispose(); + } + }); + }); + } + + private void setupProviderListener() { + fProviderListener = provider -> getDisplay().asyncExec(() -> load()); + } + + private static Image getImage(String icon) { + return ResourceManager.getPluginImage("org.eclipse.tips.ui", icon); + } + + /** + * Loads or reloads the provider list. If you want to update the read count of + * the current button or all buttons then check the {@link #updateButton()} and + * {@link #updateButtons()} methods. + * + */ + public void load() { + if (isDisposed() || fScroller.isDisposed()) { + return; + } + Arrays.stream(fScroller.getChildren()).filter(control -> !control.isDisposed()) + .forEach(control -> control.dispose()); + List<TipProvider> providers = fTipManager.getProviders(); + int spaceCount = Math.floorDiv(fScroller.getBounds().width, (fIconSize + fSpacing)); + int providerCount = providers.size(); + + if (fSliderIndex > 0 && spaceCount >= providerCount) { + fSliderIndex = 0; + } + + if (spaceCount >= providerCount) { + if (fRightButton.isEnabled()) { + fRightButton.setEnabled(false); + fLeftButton.setEnabled(false); + fLeftButton.setImage(getImage("icons/" + fIconSize + "/aright.png")); + fRightButton.setImage(getImage("icons/" + fIconSize + "/aleft.png")); + } + } else { + if (!fRightButton.isEnabled()) { + fRightButton.setEnabled(true); + fLeftButton.setEnabled(true); + fLeftButton.setImage(getImage("icons/" + fIconSize + "/aleft.png")); + fRightButton.setImage(getImage("icons/" + fIconSize + "/aright.png")); + } + } + + int emptyPixelsLeft = Math.floorMod(fScroller.getBounds().width, (fIconSize + fSpacing)); + int newSpacing = fSpacing + (emptyPixelsLeft / (spaceCount + 1)); + for (int i = 0; i < Math.min(providerCount - fSliderIndex, spaceCount); i++) { + TipProvider provider = providers.get(i + fSliderIndex); + if (fSelectedProvider == null && !provider.getTips(true).isEmpty()) { + fSelectedProvider = provider; + notifyListeners(fSelectedProvider); + } + createProviderButton(providers.get(i + fSliderIndex), newSpacing, i); + } + } + + private Composite createProviderButton(TipProvider provider, int spacing, int index) { + Composite button = new Composite(fScroller, SWT.DOUBLE_BUFFERED); + button.setToolTipText(provider.getDescription()); + button.setBackground(fScroller.getBackground()); + button.setSize(fIconSize + 4, fIconSize + 4); + button.setLocation((index * (fIconSize + spacing) + spacing - fSpacing), 2); + button.addPaintListener(e -> { + if (fSelectedProvider == provider) { + fSelectedProviderButton = button; + } + paintButton(e.gc, button, provider); + }); + button.addListener(SWT.MouseEnter, event -> button.redraw()); + button.addListener(SWT.MouseExit, event -> button.redraw()); + button.addListener(SWT.MouseUp, event -> { + if (fSelectedProvider == provider) { + return; + } + fSelectedProvider = provider; + if (fSelectedProviderButton != null && !fSelectedProviderButton.isDisposed()) { + fSelectedProviderButton.redraw(); + } + fSelectedProviderButton = button; + fSelectedProviderButton.redraw(); + notifyListeners(provider); + }); + if (fSelectedProvider == provider) { + fSelectedProviderButton = button; + } + return button; + } + + /** + * Updates the read count of the currently selected button. + */ + public void updateButton() { + if (fSelectedProviderButton != null && !fSelectedProviderButton.isDisposed()) { + getDisplay().asyncExec(() -> fSelectedProviderButton.redraw()); + } + } + + /** + * Calls redraw on all buttons to update the badge counter. + */ + public void updateButtons() { + if (!isDisposed()) { + getDisplay().asyncExec(() -> { + if (!fScroller.isDisposed()) { + for (Control control : fScroller.getChildren()) { + if (control instanceof Composite && !control.isDisposed()) { + control.redraw(); + } + } + } + }); + } + } + + /** + * Sets the {@link TipManager}. + * + * @param tipManager + * the {@link TipManager} + * @return this + */ + public Slider setTipManager(TipManager tipManager) { + fTipManager = tipManager; + fTipManager.getListenerManager().addProviderListener(fProviderListener); + fIconSize = 48; + load(); + return this; + } + + private void notifyListeners(TipProvider provider) { + fListeners.forEach(listener -> { + try { + listener.selected(provider); + } catch (Exception e) { + fTipManager.log(LogUtil.error(getClass(), e)); + } + }); + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + Point point = new Point(fIconSize * 3, fIconSize + fSpacing + fSpacing); + return point; + } + + protected void scrollRight() { + if (fSliderIndex < fTipManager.getProviders().size() - 1) { + fSliderIndex++; + load(); + } + } + + protected void scrollLeft() { + if (fSliderIndex > 0) { + fSliderIndex--; + load(); + } + } + + /** + * @return the current selected {@link TipProvider}. + */ + public TipProvider getTipProvider() { + return fSelectedProvider; + } + + /** + * Sets the passed provider as the selected provider in the slider. + * + * @param provider + * the new provider for the slider. + * + * @return this + */ + public Slider setTipProvider(TipProvider provider) { + fSelectedProvider = provider; + updateButtons(); + return this; + } + + /** + * Adds the listener to the list of listeners to be called when an event with a + * {@link TipProvider} occurs. + * + * @param listener + * the {@link ProviderSelectionListener} + * @return this + */ + public Slider addTipProviderListener(ProviderSelectionListener listener) { + fListeners.add(listener); + return this; + } + + /** + * Removes the listener from the list. + * + * @param listener + * the {@link ProviderSelectionListener} + * @return this + */ + public Slider removeTipProviderListener(ProviderSelectionListener listener) { + fListeners.remove(listener); + return this; + } + + private void paintButton(GC gc, Composite providerButton, TipProvider provider) { + gc.setAdvanced(true); + if (fSelectedProvider.equals(provider)) { + gc.drawRectangle(0, 0, fIconSize + 3, fIconSize + 3); + } else { + boolean mouseIn = getDisplay().getCursorControl() == providerButton; + if (mouseIn) { + gc.drawRectangle(0, 0, fIconSize + 3, fIconSize + 3); + } else { + gc.setBackground(fScroller.getBackground()); + } + } + gc.fillRectangle(2, 2, fIconSize, fIconSize); + Image overlay = getUnreadOverlay(providerButton, provider); + gc.drawImage(overlay, 2, 2); + if (overlay != getProviderImage(provider, selectProviderImage(provider))) { + overlay.dispose(); + } + } + + private TipImage selectProviderImage(TipProvider provider) { + return provider.getImage(); + } + + private Image getProviderImage(TipProvider provider, TipImage image) { + if (!fProviderImageCache.containsKey(provider.getID())) { + try { + fProviderImageCache.put(provider.getID(), + new Image(getDisplay(), ImageUtil.decodeToImage(image.getBase64Image()))); + } catch (Exception e) { + fTipManager.log(LogUtil.error(getClass(), e)); + return null; + } + } + return fProviderImageCache.get(provider.getID()); + } + + private Image getUnreadOverlay(Composite providerButton, TipProvider provider) { + if (provider.getTips(true).isEmpty()) { + return getProviderImage(provider, selectProviderImage(provider)); + } + GC gc2 = new GC(providerButton); + gc2.setAdvanced(true); + gc2.setFont(SWTResourceManager.getBoldFont(gc2.getFont())); + int tipCount = provider.getTips(true).size(); + Point textExtent = gc2.textExtent(tipCount + ""); + gc2.dispose(); + + Image image = null; + if (tipCount > 9) { + image = new Image(getDisplay(), textExtent.x + 8, textExtent.y + 5); + } else { + image = new Image(getDisplay(), textExtent.x + 15, textExtent.y + 5); + } + ImageData data = image.getImageData(); + data.transparentPixel = data.getPixel(0, 0); + image.dispose(); + image = new Image(getDisplay(), data); + GC gc = new GC(image); + gc.setAdvanced(true); +// if (fTipManager.mustServeReadTips()) { +// gc.setBackground(theme.getColor(TipTheme.COLOR_BADGE_TIPCOUNT_BACKGROUND)); +// } else { +// gc.setBackground(theme.getColor(TipTheme.COLOR_BADGE_UNREAD_BACKGROUND)); +// } + gc.setAlpha(210); + gc.setTextAntialias(SWT.ON); +// if (fTipManager.mustServeReadTips()) { +// gc.setForeground(theme.getColor(TipTheme.COLOR_BADGE_TIPCOUNT_FOREGROUND)); +// } else { +// gc.setForeground(theme.getColor(TipTheme.COLOR_BADGE_UNREAD_FOREGROUND)); +// } + if (tipCount > 9) { + gc.fillOval(0, 0, textExtent.x + 8, textExtent.y + 5); + gc.drawText(tipCount + "", 4, 2, true); + } else { + gc.fillOval(0, 0, textExtent.x + 15, textExtent.y + 5); + gc.drawText(tipCount + "", 8, 2, true); + } + Image result = ResourceManager.decorateImage(getProviderImage(provider, selectProviderImage(provider)), image, + SWTResourceManager.TOP_RIGHT); + image.dispose(); + gc.dispose(); + return result; + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/TipComposite.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/TipComposite.java new file mode 100644 index 000000000..2262da568 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/TipComposite.java @@ -0,0 +1,580 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.swt.SWT; +import org.eclipse.swt.browser.Browser; +import org.eclipse.swt.custom.StackLayout; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.DPIUtil; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.tips.core.IHtmlTip; +import org.eclipse.tips.core.IUrlTip; +import org.eclipse.tips.core.Tip; +import org.eclipse.tips.core.TipAction; +import org.eclipse.tips.core.TipImage; +import org.eclipse.tips.core.TipManager; +import org.eclipse.tips.core.TipProvider; +import org.eclipse.tips.core.internal.LogUtil; +import org.eclipse.tips.ui.ISwtTip; +import org.eclipse.tips.ui.internal.util.ImageUtil; +import org.eclipse.tips.ui.internal.util.ResourceManager; + +@SuppressWarnings("restriction") +public class TipComposite extends Composite implements ProviderSelectionListener { + private static final int READ_TIMER = 2000; + private TipProvider fProvider; + private Browser fBrowser; + private Slider fSlider; + private TipManager fTipManager; + private Tip fCurrentTip; + private Button fShowAtStart; + private Button fUnreadOnly; + private Button fPreviousTipButton; + private Pattern fGtkHackPattern = Pattern.compile("(.*?)([0-9]+)(.*?)([0-9]+)(.*?)"); + private Composite fSWTComposite; + private Composite fBrowserComposite; + private StackLayout fContentStack; + private Button fMultiActionMenuButton; + private Composite fNavigationBar; + private StackLayout fActionStack; + private Composite fEmptyActionComposite; + private Composite fSingleActionComposite; + private Composite fMultiActionComposite; + private Button fSingleActionButton; + private Button fMultiActionButton; + private Composite fContentComposite; + private List<Image> fActionImages = new ArrayList<>(); + private Menu fActionMenu; + + /** + * Constructor. + * + * @param parent + * the parent + * @param style + * the style + */ + public TipComposite(Composite parent, int style) { + super(parent, style); + GridLayout gridLayout_1 = new GridLayout(1, false); + gridLayout_1.marginWidth = 2; + gridLayout_1.marginHeight = 2; + setLayout(gridLayout_1); + + fContentComposite = new Composite(this, SWT.NONE); + fContentStack = new StackLayout(); + fContentComposite.setLayout(fContentStack); + GridData gd_gridComposite = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); + gd_gridComposite.widthHint = 900; + gd_gridComposite.heightHint = 600; + // gd_gridComposite.minimumWidth = -1; + // gd_gridComposite.minimumHeight = -1; + fContentComposite.setLayoutData(gd_gridComposite); + + fBrowserComposite = new Composite(fContentComposite, SWT.NONE); + fBrowserComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + fBrowser = new Browser(fBrowserComposite, SWT.NONE); + fBrowser.setJavascriptEnabled(true); + + fSWTComposite = new Composite(fContentComposite, SWT.NONE); + fSWTComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + + fNavigationBar = new Composite(this, SWT.NONE); + fNavigationBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + GridLayout gl_NavigationBar = new GridLayout(2, false); + gl_NavigationBar.horizontalSpacing = 0; + gl_NavigationBar.marginHeight = 0; + gl_NavigationBar.verticalSpacing = 0; + gl_NavigationBar.marginWidth = 0; + fNavigationBar.setLayout(gl_NavigationBar); + + Composite preferenceBar = new Composite(fNavigationBar, SWT.NONE); + FillLayout fl_composite_3 = new FillLayout(SWT.HORIZONTAL); + fl_composite_3.marginWidth = 5; + fl_composite_3.spacing = 5; + preferenceBar.setLayout(fl_composite_3); + + fShowAtStart = new Button(preferenceBar, SWT.CHECK); + fShowAtStart.setText("Show tips at startup"); + fShowAtStart.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + fTipManager.setRunAtStartup(fShowAtStart.getSelection()); + } + }); + + fUnreadOnly = new Button(preferenceBar, SWT.CHECK); + fUnreadOnly.setText("Unread only"); + fUnreadOnly.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + fTipManager.setServeReadTips(!fUnreadOnly.getSelection()); + fPreviousTipButton.setEnabled(fTipManager.mustServeReadTips()); + fSlider.load(); + getNextTip(); + } + }); + + Composite buttonBar = new Composite(fNavigationBar, SWT.NONE); + buttonBar.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1)); + GridLayout gl_buttonBar = new GridLayout(4, true); + gl_buttonBar.marginHeight = 0; + buttonBar.setLayout(gl_buttonBar); + + Composite actionComposite = new Composite(buttonBar, SWT.NONE); + fActionStack = new StackLayout(); + actionComposite.setLayout(fActionStack); + actionComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + + fSingleActionComposite = new Composite(actionComposite, SWT.NONE); + GridLayout gl_SingleActionComposite = new GridLayout(1, false); + gl_SingleActionComposite.marginWidth = 0; + fSingleActionComposite.setLayout(gl_SingleActionComposite); + + fSingleActionButton = new Button(fSingleActionComposite, SWT.NONE); + fSingleActionButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + fSingleActionButton.setText("More..."); + fSingleActionButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + runTipAction(fCurrentTip.getActions().get(0)); + } + }); + + fMultiActionComposite = new Composite(actionComposite, SWT.NONE); + GridLayout gl_MultiActionComposite = new GridLayout(2, false); + gl_MultiActionComposite.marginWidth = 0; + gl_MultiActionComposite.verticalSpacing = 0; + gl_MultiActionComposite.horizontalSpacing = 0; + fMultiActionComposite.setLayout(gl_MultiActionComposite); + + fMultiActionButton = new Button(fMultiActionComposite, SWT.NONE); + fMultiActionButton.setText("New Button"); + fMultiActionButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + runTipAction(fCurrentTip.getActions().get(0)); + } + }); + + fMultiActionMenuButton = new Button(fMultiActionComposite, SWT.NONE); + fMultiActionMenuButton.setImage(ResourceManager.getPluginImage("org.eclipse.tips.ui", "icons/popup_menu.gif")); + fMultiActionMenuButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + showActionMenu(); + } + }); + + fEmptyActionComposite = new Composite(actionComposite, SWT.NONE); + + fPreviousTipButton = new Button(buttonBar, SWT.NONE); + fPreviousTipButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + fPreviousTipButton.setText("Previous Tip"); + fPreviousTipButton.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + getPreviousTip(); + } + }); + fPreviousTipButton.setEnabled(false); + + Button btnNextTip = new Button(buttonBar, SWT.NONE); + btnNextTip.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + btnNextTip.setText("Next Tip"); + btnNextTip.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + getNextTip(); + } + }); + + Button btnClose = new Button(buttonBar, SWT.NONE); + btnClose.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + getParent().dispose(); + } + }); + btnClose.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + btnClose.setText("Close"); + + Label label_1 = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL); + label_1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1)); + + fSlider = new Slider(this, SWT.NONE); + GridLayout gridLayout = (GridLayout) fSlider.getLayout(); + gridLayout.verticalSpacing = 0; + gridLayout.marginWidth = 0; + gridLayout.horizontalSpacing = 0; + fSlider.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, false, 1, 1)); + fContentStack.topControl = fBrowserComposite; + fSlider.addTipProviderListener(this); + } + + private void showActionMenu() { + Rectangle rect = fMultiActionButton.getBounds(); + Point pt = new Point(rect.x - 1, rect.y + rect.height); + pt = fMultiActionButton.toDisplay(pt); + fActionMenu.setLocation(pt.x, pt.y); + fActionMenu.setVisible(true); + } + + private void runTipAction(TipAction tipAction) { + Job job = new Job("Running " + tipAction.getTooltip()) { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + tipAction.getRunner().run(); + } catch (Exception e) { + IStatus status = LogUtil.error(getClass(), e); + fTipManager.log(status); + return status; + } + return Status.OK_STATUS; + } + }; + job.setUser(true); + job.schedule(); + } + + /** + * Sets the selected provider. + * + * @param provider + * the {@link TipProvider} + */ + public void setProvider(TipProvider provider) { + fProvider = provider; + fSlider.setTipProvider(provider); + getCurrentTip(); + } + + /** + * Schedules a TimerTask that is executed after {@value #READ_TIMER} + * milliseconds after which the tip is marked as read. + */ + private void hitTimer() { + Tip timerTip = fCurrentTip; + Timer timer = new Timer("Tip read timer"); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (timerTip == fCurrentTip) { + fTipManager.setAsRead(timerTip); + fSlider.updateButtons(); + } + timer.cancel(); + } + }, READ_TIMER); + } + + private void getPreviousTip() { + processTip(fProvider.getPreviousTip()); + } + + private void getNextTip() { + if (fProvider.getTips(true).isEmpty() && !fTipManager.getProviders().isEmpty()) { + fProvider.getNextTip(); // advance current tip + for (TipProvider provider : fTipManager.getProviders()) { + if (!provider.getTips(true).isEmpty()) { + setProvider(provider); + break; + } + } + } + processTip(fProvider.getNextTip()); + } + + private void getCurrentTip() { + processTip(fProvider.getCurrentTip()); + } + + private void processTip(Tip tip) { + fCurrentTip = tip; + hitTimer(); + enableActionButtons(tip); + prepareForHTML(); + loadContent(tip); + } + + private void loadContent(Tip tip) { + if (tip instanceof ISwtTip) { + loadContentSWT(tip); + } else if (tip instanceof IHtmlTip) { + loadContentHtml((IHtmlTip) tip); + } else if (tip instanceof IUrlTip) { + loadContentUrl((IUrlTip) tip); + } else { + fTipManager.log(LogUtil.error(getClass(), "Unknown Tip implementation: " + tip)) ; + } + fContentComposite.requestLayout(); + } + + private void loadContentHtml(IHtmlTip tip) { + try { + fBrowser.setText(getScaling() + getHTML(tip).trim()); + } catch (IOException e) { + fTipManager.log(LogUtil.error(getClass(), e)); + } + } + + private void loadContentUrl(IUrlTip tip) { + try { + fBrowser.setUrl(FileLocator.resolve(tip.getURL()).toString()); + } catch (IOException e) { + fTipManager.log(LogUtil.error(getClass(), e)); + } + } + + private void loadContentSWT(Tip tip) { + for (Control control : fSWTComposite.getChildren()) { + control.dispose(); + } + fContentStack.topControl = fSWTComposite; + ((ISwtTip) tip).createControl(fSWTComposite); + fSWTComposite.requestLayout(); + } + + private void prepareForHTML() { + fContentStack.topControl = fBrowserComposite; + loadTimeOutScript(); + fBrowserComposite.requestLayout(); + } + + /** + * Sets content in the browser that displays a message after 500ms if the Tip + * could not load fast enough. + */ + private void loadTimeOutScript() { + fBrowser.setText(getScaling() + getLoadingScript(500)); + while (!getShell().isDisposed()) { + if (!getDisplay().readAndDispatch()) { + break; + } + } + } + + private void enableActionButtons(Tip tip) { + disposeActionImages(); + if (tip.getActions().isEmpty()) { + fActionStack.topControl = fEmptyActionComposite; + } else if (tip.getActions().size() == 1) { + TipAction action = tip.getActions().get(0); + fActionStack.topControl = fSingleActionComposite; + fSingleActionButton.setImage(getActionImage(action.getTipImage())); + fSingleActionButton.setText(action.getText()); + fSingleActionButton.setToolTipText(action.getTooltip()); + blinkActionComposite(fSingleActionComposite); + } else { + TipAction action = tip.getActions().get(0); + fActionStack.topControl = fMultiActionComposite; + fMultiActionButton.setImage(getActionImage(tip.getActions().get(0).getTipImage())); + fMultiActionButton.setText(action.getText()); + fMultiActionButton.setToolTipText(action.getTooltip()); + loadActionMenu(tip); + blinkActionComposite(fMultiActionComposite); + } + fEmptyActionComposite.getParent().requestLayout(); + fNavigationBar.requestLayout(); + } + + private void disposeActionImages() { + fActionImages.forEach(img -> img.dispose()); + } + + private void loadActionMenu(Tip pTip) { + if (fActionMenu != null) { + fActionMenu.dispose(); + } + fActionMenu = new Menu(fContentComposite.getShell(), SWT.POP_UP); + pTip.getActions().subList(1, pTip.getActions().size()).forEach(action -> { + MenuItem item = new MenuItem(fActionMenu, SWT.PUSH); + item.setText(action.getText()); + item.setToolTipText(action.getTooltip()); + item.setText(action.getText()); + item.setImage(getActionImage(action.getTipImage())); + item.addListener(SWT.Selection, e -> runTipAction(action)); + }); + } + + private void blinkActionComposite(Composite composite) { + Color bg = composite.getParent().getBackground(); + Color red = getDisplay().getSystemColor(SWT.COLOR_RED); + boolean flip = false; + for (int i = 1; i < 6; i++) { + boolean flop = flip; + if (!composite.isDisposed()) { + getDisplay().timerExec(i * 200, () -> { + if (!composite.isDisposed()) { + composite.getParent().setBackground(flop ? bg : red); + } + }); + } + flip = !flip; + } + } + + private Image getActionImage(TipImage tipImage) { + if (tipImage == null) { + return null; + } + try { + Image image = new Image(getDisplay(), ImageUtil.decodeToImage(tipImage.getBase64Image())); + if (image != null) { + fActionImages.add(image); + return image; + } + } catch (IOException e) { + fTipManager.log(LogUtil.error(getClass(), e)); + } + return null; + } + + /** + * Get the timeout script in case the tips takes too to load. + * + * @param timeout + * the timeout in milliseconds + * @return the script + */ + private static String getLoadingScript(int timeout) { + return "<style>div{position:fixed;top:50%;left:40%}</style>" + "<div id=\"txt\"></div>" + + "<script>var wss=function(){document.getElementById(\"txt\").innerHTML=\"Loading next Tip...\"};window.setTimeout(wss," + + timeout + ");</script>"; + } + + private String getHTML(IHtmlTip tip) throws IOException { + String encodedImage = encodeImage(tip); + return tip.getHTML() + encodedImage; + } + + private static String getScaling() { + if (Platform.isRunning() && Platform.getWS().startsWith("gtk")) { + int deviceZoom = DPIUtil.getDeviceZoom(); + int zoom = deviceZoom; + return "<style>" + "body {" + " zoom: " + zoom + "%;" + "}</style> "; + } + return ""; + } + + private String encodeImage(IHtmlTip tip) throws IOException { + TipImage image = tip.getImage(); + if (image == null) { + return ""; + } + return encodeImageFromBase64(image); + } + + private String encodeImageFromBase64(TipImage image) throws IOException { + int width = fBrowser.getClientArea().width; + int height = Math.min(fBrowser.getClientArea().height / 2, (2 * (width / 3))); + String attributes = gtkHack(image.getIMGAttributes(width, height).trim()); + String encoded = "" // + + "<center> <img " // + + attributes // + + " src=\"" // + + image.getBase64Image() // + + "\"></center><br/>"; + return encoded; + } + + private String gtkHack(String imageAttribute) { + if (!Platform.isRunning()) { + return imageAttribute; + } + if (!Platform.getWS().startsWith("gtk")) { + return imageAttribute; + } + Matcher m = fGtkHackPattern.matcher(imageAttribute); + if (!m.matches()) { + return imageAttribute; + } + return m.group(1) + (Integer.parseInt(m.group(2)) * 120 / 100) + m.group(3) + + (Integer.parseInt(m.group(4)) * 120 / 100) + m.group(5); + } + + @Override + protected void checkSubclass() { + } + + /** + * @return the {@link Browser} widget + */ + public Browser getBrowser() { + return fBrowser; + } + + /** + * @return the {@link Slider} widget + */ + public Slider getSlider() { + return fSlider; + } + + @Override + public void selected(TipProvider provider) { + setProvider(provider); + } + + /** + * Sets the {@link TipManager} + * + * @param tipManager + * the {@link TipManager} that opened the dialog. + */ + public void setTipManager(TipManager tipManager) { + fTipManager = tipManager; + + getDisplay().syncExec(() -> { + fSlider.setTipManager(fTipManager); + fShowAtStart.setSelection(fTipManager.isRunAtStartup()); + fUnreadOnly.setSelection(!fTipManager.mustServeReadTips()); + fPreviousTipButton.setEnabled(fTipManager.mustServeReadTips()); + }); + } + + @Override + public void dispose() { + disposeActionImages(); + super.dispose(); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/TipDialog.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/TipDialog.java new file mode 100644 index 000000000..a31398a8d --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/TipDialog.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tips.core.TipManager; + +public class TipDialog extends Shell { + + /** + * When passed as style, the default style will be used. + */ + public static final int DEFAULT_STYLE = -1; + private TipManager fTipManager; + private TipComposite fTipComposite; + + /** + * Creates the Tip Dialog. + * + * @param display + * the {@link Display} + * @param tipManager + * the {@link TipManager} + * @param style + * the {@link Shell} style or {@link #DEFAULT_STYLE} for + * <code>SWT.DIALOG_TRIM | SWT.RESIZE | SWT.CLOSE</code> + */ + public TipDialog(Shell display, TipManager tipManager, int style) { + super(display, style == DEFAULT_STYLE ? SWT.DIALOG_TRIM | SWT.RESIZE | SWT.CLOSE : style); + fTipManager = tipManager; + setLayout(new FillLayout(SWT.HORIZONTAL)); + fTipComposite = new TipComposite(this, SWT.NONE); + pack(); + setLocation(getShell().getMonitor().getClientArea().width / 2 - getSize().x / 2, + getShell().getMonitor().getClientArea().height / 2 - getSize().y / 2); + setText("Tip of the Day"); + } + + @Override + public void open() { + super.open(); + fTipComposite.setTipManager(fTipManager); + } + + @Override + protected void checkSubclass() { + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/package-info.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/package-info.java new file mode 100644 index 000000000..ba28b4609 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/package-info.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Internal classes of the SWT Tip Dialog. You can use these classes as an + * example on how to build your own Tip Dialog. + * + */ +package org.eclipse.tips.ui.internal;
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/DateUtil.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/DateUtil.java new file mode 100644 index 000000000..46ff7d643 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/DateUtil.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Date utilities. + * + */ +public class DateUtil { + + /** + * Convenience method that creates a date from a dd/mm/yy string. + * + * @param dateYYMMDD + * the date in a dd/mm/yy format, e.g. "01/01/2017" + * @return the date + * @throws RuntimeException + * if the date is not correct + */ + public static Date getDateFromYYMMDD(String dateYYMMDD) { + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); + try { + return sdf.parse(dateYYMMDD); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/ImageUtil.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/ImageUtil.java new file mode 100644 index 000000000..7598d0956 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/ImageUtil.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.Base64.Decoder; +import java.util.Base64.Encoder; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; + +/** + * Image helper class. + * + */ +public class ImageUtil { + + private static final String COMMA = ","; + + /** + * Calculate a height that will fit in the proposed rectangle given the passed + * aspect ratio. + * + * @param aspectRatio + * the aspect ration, e.g. 1.5 for a 3/2 ratio (width/height). + * @param widthHint + * the available width in the viewport + * @param heightHint + * the available height in the viewport + * @return the maximum height that will fit in the passed rectangle. + */ + public static int getHeight(double aspectRatio, int widthHint, int heightHint) { + return (int) Math.min(heightHint, widthHint / aspectRatio); + } + + /** + * Calculate a width that will fit in the proposed rectangle given the passed + * aspect ratio. + * + * @param aspectRatio + * the aspect ration, e.g. 1.5 for a 3/2 ratio (width/height). + * @param widthHint + * the available width in the viewport + * @param heightHint + * the available height in the viewport + * @return the maximum width that will fit in the rectangle. + */ + public static int getWidth(double aspectRatio, int widthHint, int heightHint) { + return (int) Math.min(widthHint, heightHint * aspectRatio); + } + + /** + * Converts a base 64 encoded image into and ImageData object. + * + * @param base64Image + * the images as a base64 string. + * @return the image decoded as base64 + * @throws IOException + * in case of IO problems + */ + public static ImageData decodeToImage(String base64Image) throws IOException { + if (base64Image == null) { + return null; + } + String image = processB64String(base64Image); + Decoder decoder = Base64.getDecoder(); + byte[] imageByte = decoder.decode(image); + try (ByteArrayInputStream bis = new ByteArrayInputStream(imageByte)) { + ImageData imageData = new ImageData(bis); + return imageData; + } + } + + /** + * Transforms the passed image to a Base64 String. + * + * @param image + * the image to convert, null in is null out. + * @param format + * see {@link ImageLoader#save(java.io.OutputStream, int)} + * @return The encoded image in base 64 or null if the passed image was null. + */ + public static String decodeFromImage(Image image, int format) { + if (image == null) { + return null; + } + ImageLoader loader = new ImageLoader(); + loader.data = new ImageData[] { image.getImageData() }; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + loader.save(bos, format); + Encoder encoder = Base64.getEncoder(); + return getHeader(format) + encoder.encodeToString(bos.toByteArray()); + } + + private static String getHeader(int format) { + return "data:image/" + getExtension(format) + ";base64,"; + } + + private static String getExtension(int format) { + switch (format) { + case SWT.IMAGE_BMP: + return "bmp"; + case SWT.IMAGE_BMP_RLE: + return "bmp"; + case SWT.IMAGE_GIF: + return "gif"; + case SWT.IMAGE_ICO: + return "ico"; + case SWT.IMAGE_JPEG: + return "jpeg"; + default: + return "png"; + } + } + + private static String processB64String(String base64Image) { + int index = base64Image.substring(0, 50).indexOf(COMMA) + 1; + return base64Image.substring(index); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/ResourceManager.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/ResourceManager.java new file mode 100644 index 000000000..31e4919cb --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/ResourceManager.java @@ -0,0 +1,435 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Google, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal.util; + +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.CompositeImageDescriptor; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.osgi.framework.Bundle; + +/** + * Utility class for managing OS resources associated with SWT/JFace controls + * such as colors, fonts, images, etc. + * + * !!! IMPORTANT !!! Application code must explicitly invoke the + * <code>dispose()</code> method to release the operating system resources + * managed by cached objects when those objects and OS resources are no longer + * needed (e.g. on application shutdown) + * + * This class may be freely distributed as part of any application or plugin. + * <p> + * + * @author scheglov_ke + * @author Dan Rubel + */ +public class ResourceManager extends SWTResourceManager { + //////////////////////////////////////////////////////////////////////////// + // + // Image + // + //////////////////////////////////////////////////////////////////////////// + private static Map<ImageDescriptor, Image> m_descriptorImageMap = new HashMap<ImageDescriptor, Image>(); + + /** + * Returns an {@link ImageDescriptor} stored in the file at the specified path + * relative to the specified class. + * + * @param clazz + * the {@link Class} relative to which to find the image descriptor. + * @param path + * the path to the image file. + * @return the {@link ImageDescriptor} stored in the file at the specified path. + */ + public static ImageDescriptor getImageDescriptor(Class<?> clazz, String path) { + return ImageDescriptor.createFromFile(clazz, path); + } + + /** + * Returns an {@link ImageDescriptor} stored in the file at the specified path. + * + * @param path + * the path to the image file. + * @return the {@link ImageDescriptor} stored in the file at the specified path. + */ + public static ImageDescriptor getImageDescriptor(String path) { + try { + return ImageDescriptor.createFromURL(new File(path).toURI().toURL()); + } catch (MalformedURLException e) { + return null; + } + } + + /** + * Returns an {@link Image} based on the specified {@link ImageDescriptor}. + * + * @param descriptor + * the {@link ImageDescriptor} for the {@link Image}. + * @return the {@link Image} based on the specified {@link ImageDescriptor}. + */ + public static Image getImage(ImageDescriptor descriptor) { + if (descriptor == null) { + return null; + } + Image image = m_descriptorImageMap.get(descriptor); + if (image == null) { + image = descriptor.createImage(); + m_descriptorImageMap.put(descriptor, image); + } + return image; + } + + /** + * Maps images to decorated images. + */ + @SuppressWarnings("unchecked") + private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY]; + + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated. + * @param decorator + * the {@link Image} to decorate the base image. + * @return {@link Image} The resulting decorated image. + */ + public static Image decorateImage(Image baseImage, Image decorator) { + return decorateImage(baseImage, decorator, BOTTOM_RIGHT); + } + + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated. + * @param decorator + * the {@link Image} to decorate the base image. + * @param corner + * the corner to place decorator image. + * @return the resulting decorated {@link Image}. + */ + public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { + if (corner <= 0 || corner >= LAST_CORNER_KEY) { + throw new IllegalArgumentException("Wrong decorate corner"); + } + Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner]; + if (cornerDecoratedImageMap == null) { + cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>(); + m_decoratedImageMap[corner] = cornerDecoratedImageMap; + } + Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage); + if (decoratedMap == null) { + decoratedMap = new HashMap<Image, Image>(); + cornerDecoratedImageMap.put(baseImage, decoratedMap); + } + // + Image result = decoratedMap.get(decorator); + if (result == null) { + final Rectangle bib = baseImage.getBounds(); + final Rectangle dib = decorator.getBounds(); + final Point baseImageSize = new Point(bib.width, bib.height); + CompositeImageDescriptor compositImageDesc = new CompositeImageDescriptor() { + @Override + protected void drawCompositeImage(int width, int height) { + drawImage(createCachedImageDataProvider(baseImage), 0, 0); + if (corner == TOP_LEFT) { + drawImage(createCachedImageDataProvider(decorator), 0, 0); + } else if (corner == TOP_RIGHT) { + drawImage(createCachedImageDataProvider(decorator), bib.width - dib.width, 0); + } else if (corner == BOTTOM_LEFT) { + drawImage(createCachedImageDataProvider(decorator), 0, bib.height - dib.height); + } else if (corner == BOTTOM_RIGHT) { + drawImage(createCachedImageDataProvider(decorator), bib.width - dib.width, + bib.height - dib.height); + } + } + + @Override + protected Point getSize() { + return baseImageSize; + } + }; + // + result = compositImageDesc.createImage(); + decoratedMap.put(decorator, result); + } + return result; + } + + /** + * Dispose all of the cached images. + */ + public static void disposeImages() { + SWTResourceManager.disposeImages(); + // dispose ImageDescriptor images + { + for (Image image : m_descriptorImageMap.values()) { + image.dispose(); + } + m_descriptorImageMap.clear(); + } + // dispose decorated images + for (Map<Image, Map<Image, Image>> cornerDecoratedImageMap : m_decoratedImageMap) { + if (cornerDecoratedImageMap != null) { + for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) { + for (Image image : decoratedMap.values()) { + image.dispose(); + } + decoratedMap.clear(); + } + cornerDecoratedImageMap.clear(); + } + } + // dispose plugin images + { + for (Image image : m_URLImageMap.values()) { + image.dispose(); + } + m_URLImageMap.clear(); + } + } + + //////////////////////////////////////////////////////////////////////////// + // + // Plugin images support + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps URL to images. + */ + private static Map<String, Image> m_URLImageMap = new HashMap<String, Image>(); + + /** + * Provider for plugin resources, used by WindowBuilder at design time. + */ + public interface PluginResourceProvider { + URL getEntry(String symbolicName, String path); + } + + /** + * Instance of {@link PluginResourceProvider}, used by WindowBuilder at design + * time. + */ + private static PluginResourceProvider m_designTimePluginResourceProvider = null; + + /** + * Returns an {@link Image} based on a plugin and file path. + * + * @param plugin + * the plugin {@link Object} containing the image + * @param name + * the path to the image within the plugin + * @return the {@link Image} stored in the file at the specified path + * + * @deprecated Use {@link #getPluginImage(String, String)} instead. + */ + @Deprecated + public static Image getPluginImage(Object plugin, String name) { + try { + URL url = getPluginImageURL(plugin, name); + if (url != null) { + return getPluginImageFromUrl(url); + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + + /** + * Returns an {@link Image} based on a {@link Bundle} and resource entry path. + * + * @param symbolicName + * the symbolic name of the {@link Bundle}. + * @param path + * the path of the resource entry. + * @return the {@link Image} stored in the file at the specified path. + */ + public static Image getPluginImage(String symbolicName, String path) { + try { + URL url = getPluginImageURL(symbolicName, path); + if (url != null) { + return getPluginImageFromUrl(url); + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + + /** + * Returns an {@link Image} based on given {@link URL}. + */ + private static Image getPluginImageFromUrl(URL url) { + try { + try { + String key = url.toExternalForm(); + Image image = m_URLImageMap.get(key); + if (image == null) { + try (InputStream stream = url.openStream()) { + image = getImage(stream); + m_URLImageMap.put(key, image); + } + } + return image; + } catch (Throwable e) { + // Ignore any exceptions + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + + /** + * Returns an {@link ImageDescriptor} based on a plugin and file path. + * + * @param plugin + * the plugin {@link Object} containing the image. + * @param name + * the path to th eimage within the plugin. + * @return the {@link ImageDescriptor} stored in the file at the specified path. + * + * @deprecated Use {@link #getPluginImageDescriptor(String, String)} instead. + */ + @Deprecated + public static ImageDescriptor getPluginImageDescriptor(Object plugin, String name) { + try { + try { + URL url = getPluginImageURL(plugin, name); + return ImageDescriptor.createFromURL(url); + } catch (Throwable e) { + // Ignore any exceptions + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + + /** + * Returns an {@link ImageDescriptor} based on a {@link Bundle} and resource + * entry path. + * + * @param symbolicName + * the symbolic name of the {@link Bundle}. + * @param path + * the path of the resource entry. + * @return the {@link ImageDescriptor} based on a {@link Bundle} and resource + * entry path. + */ + public static ImageDescriptor getPluginImageDescriptor(String symbolicName, String path) { + try { + URL url = getPluginImageURL(symbolicName, path); + if (url != null) { + return ImageDescriptor.createFromURL(url); + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + + /** + * Returns an {@link URL} based on a {@link Bundle} and resource entry path. + */ + private static URL getPluginImageURL(String symbolicName, String path) { + // try runtime plugins + { + Bundle bundle = Platform.getBundle(symbolicName); + if (bundle != null) { + return bundle.getEntry(path); + } + } + // try design time provider + if (m_designTimePluginResourceProvider != null) { + return m_designTimePluginResourceProvider.getEntry(symbolicName, path); + } + // no such resource + return null; + } + + /** + * Returns an {@link URL} based on a plugin and file path. + * + * @param plugin + * the plugin {@link Object} containing the file path. + * @param name + * the file path. + * @return the {@link URL} representing the file at the specified path. + * @throws Exception + */ + private static URL getPluginImageURL(Object plugin, String name) throws Exception { + // try to work with 'plugin' as with OSGI BundleContext + try { + Class<?> BundleClass = Class.forName("org.osgi.framework.Bundle"); //$NON-NLS-1$ + Class<?> BundleContextClass = Class.forName("org.osgi.framework.BundleContext"); //$NON-NLS-1$ + if (BundleContextClass.isAssignableFrom(plugin.getClass())) { + Method getBundleMethod = BundleContextClass.getMethod("getBundle", new Class[0]); //$NON-NLS-1$ + Object bundle = getBundleMethod.invoke(plugin, new Object[0]); + // + Class<?> PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$ + Constructor<?> pathConstructor = PathClass.getConstructor(new Class[] { String.class }); + Object path = pathConstructor.newInstance(new Object[] { name }); + // + Class<?> IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$ + Class<?> PlatformClass = Class.forName("org.eclipse.core.runtime.Platform"); //$NON-NLS-1$ + Method findMethod = PlatformClass.getMethod("find", new Class[] { BundleClass, IPathClass }); //$NON-NLS-1$ + return (URL) findMethod.invoke(null, new Object[] { bundle, path }); + } + } catch (Throwable e) { + // Ignore any exceptions + } + // else work with 'plugin' as with usual Eclipse plugin + { + Class<?> PluginClass = Class.forName("org.eclipse.core.runtime.Plugin"); //$NON-NLS-1$ + if (PluginClass.isAssignableFrom(plugin.getClass())) { + // + Class<?> PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$ + Constructor<?> pathConstructor = PathClass.getConstructor(new Class[] { String.class }); + Object path = pathConstructor.newInstance(new Object[] { name }); + // + Class<?> IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$ + Method findMethod = PluginClass.getMethod("find", new Class[] { IPathClass }); //$NON-NLS-1$ + return (URL) findMethod.invoke(plugin, new Object[] { path }); + } + } + return null; + } + + //////////////////////////////////////////////////////////////////////////// + // + // General + // + //////////////////////////////////////////////////////////////////////////// + /** + * Dispose of cached objects and their underlying OS resources. This should only + * be called when the cached objects are no longer needed (e.g. on application + * shutdown). + */ + public static void dispose() { + disposeColors(); + disposeFonts(); + disposeImages(); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/SWTResourceManager.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/SWTResourceManager.java new file mode 100644 index 000000000..e3f0cd524 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/SWTResourceManager.java @@ -0,0 +1,488 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Google, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.tips.ui.internal.util; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +/** + * Utility class for managing OS resources associated with SWT controls such as + * colors, fonts, images, etc. + * <p> + * !!! IMPORTANT !!! Application code must explicitly invoke the + * <code>dispose()</code> method to release the operating system resources + * managed by cached objects when those objects and OS resources are no longer + * needed (e.g. on application shutdown) + * <p> + * This class may be freely distributed as part of any application or plugin. + * <p> + * + * @author scheglov_ke + * @author Dan Rubel + */ +public class SWTResourceManager { + //////////////////////////////////////////////////////////////////////////// + // + // Color + // + //////////////////////////////////////////////////////////////////////////// + private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>(); + + /** + * Returns the system {@link Color} matching the specific ID. + * + * @param systemColorID + * the ID value for the color + * @return the system {@link Color} matching the specific ID + */ + public static Color getColor(int systemColorID) { + Display display = Display.getCurrent(); + return display.getSystemColor(systemColorID); + } + + /** + * Returns a {@link Color} given its red, green and blue component values. + * + * @param r + * the red component of the color + * @param g + * the green component of the color + * @param b + * the blue component of the color + * @return the {@link Color} matching the given red, green and blue component + * values + */ + public static Color getColor(int r, int g, int b) { + return getColor(new RGB(r, g, b)); + } + + /** + * Returns a {@link Color} given its RGB value. + * + * @param rgb + * the {@link RGB} value of the color + * @return the {@link Color} matching the RGB value + */ + public static Color getColor(RGB rgb) { + Color color = m_colorMap.get(rgb); + if (color == null) { + Display display = Display.getCurrent(); + color = new Color(display, rgb); + m_colorMap.put(rgb, color); + } + return color; + } + + /** + * Dispose of all the cached {@link Color}'s. + */ + public static void disposeColors() { + for (Color color : m_colorMap.values()) { + color.dispose(); + } + m_colorMap.clear(); + } + + //////////////////////////////////////////////////////////////////////////// + // + // Image + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps image paths to images. + */ + private static Map<String, Image> m_imageMap = new HashMap<String, Image>(); + + /** + * Returns an {@link Image} encoded by the specified {@link InputStream}. + * + * @param stream + * the {@link InputStream} encoding the image data + * @return the {@link Image} encoded by the specified input stream + */ + protected static Image getImage(InputStream stream) throws IOException { + try { + Display display = Display.getCurrent(); + ImageData data = new ImageData(stream); + if (data.transparentPixel > 0) { + return new Image(display, data, data.getTransparencyMask()); + } + return new Image(display, data); + } finally { + stream.close(); + } + } + + /** + * Returns an {@link Image} stored in the file at the specified path. + * + * @param path + * the path to the image file + * @return the {@link Image} stored in the file at the specified path + */ + public static Image getImage(String path) { + Image image = m_imageMap.get(path); + if (image == null) { + try { + image = getImage(new FileInputStream(path)); + m_imageMap.put(path, image); + } catch (Exception e) { + image = getMissingImage(); + m_imageMap.put(path, image); + } + } + return image; + } + + /** + * Returns an {@link Image} stored in the file at the specified path relative to + * the specified class. + * + * @param clazz + * the {@link Class} relative to which to find the image + * @param path + * the path to the image file, if starts with <code>'/'</code> + * @return the {@link Image} stored in the file at the specified path + */ + public static Image getImage(Class<?> clazz, String path) { + String key = clazz.getName() + '|' + path; + Image image = m_imageMap.get(key); + if (image == null) { + try { + image = getImage(clazz.getResourceAsStream(path)); + m_imageMap.put(key, image); + } catch (Exception e) { + image = getMissingImage(); + m_imageMap.put(key, image); + } + } + return image; + } + + private static final int MISSING_IMAGE_SIZE = 10; + + /** + * @return the small {@link Image} that can be used as placeholder for missing + * image. + */ + private static Image getMissingImage() { + Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); + // + GC gc = new GC(image); + gc.setBackground(getColor(SWT.COLOR_RED)); + gc.fillRectangle(0, 0, MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); + gc.dispose(); + // + return image; + } + + /** + * Style constant for placing decorator image in top left corner of base image. + */ + public static final int TOP_LEFT = 1; + /** + * Style constant for placing decorator image in top right corner of base image. + */ + public static final int TOP_RIGHT = 2; + /** + * Style constant for placing decorator image in bottom left corner of base + * image. + */ + public static final int BOTTOM_LEFT = 3; + /** + * Style constant for placing decorator image in bottom right corner of base + * image. + */ + public static final int BOTTOM_RIGHT = 4; + /** + * Internal value. + */ + protected static final int LAST_CORNER_KEY = 5; + /** + * Maps images to decorated images. + */ + @SuppressWarnings("unchecked") + private static Map<Image, Map<Image, Image>>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY]; + + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated + * @param decorator + * the {@link Image} to decorate the base image + * @return {@link Image} The resulting decorated image + */ + public static Image decorateImage(Image baseImage, Image decorator) { + return decorateImage(baseImage, decorator, BOTTOM_RIGHT); + } + + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated + * @param decorator + * the {@link Image} to decorate the base image + * @param corner + * the corner to place decorator image + * @return the resulting decorated {@link Image} + */ + public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { + if (corner <= 0 || corner >= LAST_CORNER_KEY) { + throw new IllegalArgumentException("Wrong decorate corner"); + } + Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner]; + if (cornerDecoratedImageMap == null) { + cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>(); + m_decoratedImageMap[corner] = cornerDecoratedImageMap; + } + Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage); + if (decoratedMap == null) { + decoratedMap = new HashMap<Image, Image>(); + cornerDecoratedImageMap.put(baseImage, decoratedMap); + } + // + Image result = decoratedMap.get(decorator); + if (result == null) { + Rectangle bib = baseImage.getBounds(); + Rectangle dib = decorator.getBounds(); + // + result = new Image(Display.getCurrent(), bib.width, bib.height); + // + GC gc = new GC(result); + gc.drawImage(baseImage, 0, 0); + if (corner == TOP_LEFT) { + gc.drawImage(decorator, 0, 0); + } else if (corner == TOP_RIGHT) { + gc.drawImage(decorator, bib.width - dib.width, 0); + } else if (corner == BOTTOM_LEFT) { + gc.drawImage(decorator, 0, bib.height - dib.height); + } else if (corner == BOTTOM_RIGHT) { + gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height); + } + gc.dispose(); + // + decoratedMap.put(decorator, result); + } + return result; + } + + /** + * Dispose all of the cached {@link Image}'s. + */ + public static void disposeImages() { + // dispose loaded images + { + for (Image image : m_imageMap.values()) { + image.dispose(); + } + m_imageMap.clear(); + } + // dispose decorated images + for (Map<Image, Map<Image, Image>> cornerDecoratedImageMap : m_decoratedImageMap) { + if (cornerDecoratedImageMap != null) { + for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) { + for (Image image : decoratedMap.values()) { + image.dispose(); + } + decoratedMap.clear(); + } + cornerDecoratedImageMap.clear(); + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // + // Font + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps font names to fonts. + */ + private static Map<String, Font> m_fontMap = new HashMap<String, Font>(); + /** + * Maps fonts to their bold versions. + */ + private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>(); + + /** + * Returns a {@link Font} based on its name, height and style. + * + * @param name + * the name of the font + * @param height + * the height of the font + * @param style + * the style of the font + * @return {@link Font} The font matching the name, height and style + */ + public static Font getFont(String name, int height, int style) { + return getFont(name, height, style, false, false); + } + + /** + * Returns a {@link Font} based on its name, height and style. Windows-specific + * strikeout and underline flags are also supported. + * + * @param name + * the name of the font + * @param size + * the size of the font + * @param style + * the style of the font + * @param strikeout + * the strikeout flag (warning: Windows only) + * @param underline + * the underline flag (warning: Windows only) + * @return {@link Font} The font matching the name, height, style, strikeout and + * underline + */ + public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) { + String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline; + Font font = m_fontMap.get(fontName); + if (font == null) { + FontData fontData = new FontData(name, size, style); + if (strikeout || underline) { + try { + Class<?> logFontClass = Class.forName("org.eclipse.swt.internal.win32.LOGFONT"); //$NON-NLS-1$ + Object logFont = FontData.class.getField("data").get(fontData); //$NON-NLS-1$ + if (logFont != null && logFontClass != null) { + if (strikeout) { + logFontClass.getField("lfStrikeOut").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ + } + if (underline) { + logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ + } + } + } catch (Throwable e) { + System.err.println( + "Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + font = new Font(Display.getCurrent(), fontData); + m_fontMap.put(fontName, font); + } + return font; + } + + /** + * Returns a bold version of the given {@link Font}. + * + * @param baseFont + * the {@link Font} for which a bold version is desired + * @return the bold version of the given {@link Font} + */ + public static Font getBoldFont(Font baseFont) { + Font font = m_fontToBoldFontMap.get(baseFont); + if (font == null) { + FontData fontDatas[] = baseFont.getFontData(); + FontData data = fontDatas[0]; + font = new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD); + m_fontToBoldFontMap.put(baseFont, font); + } + return font; + } + + /** + * Dispose all of the cached {@link Font}'s. + */ + public static void disposeFonts() { + // clear fonts + for (Font font : m_fontMap.values()) { + font.dispose(); + } + m_fontMap.clear(); + // clear bold fonts + for (Font font : m_fontToBoldFontMap.values()) { + font.dispose(); + } + m_fontToBoldFontMap.clear(); + } + + //////////////////////////////////////////////////////////////////////////// + // + // Cursor + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps IDs to cursors. + */ + private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>(); + + /** + * Returns the system cursor matching the specific ID. + * + * @param id + * int The ID value for the cursor + * @return Cursor The system cursor matching the specific ID + */ + public static Cursor getCursor(int id) { + Integer key = Integer.valueOf(id); + Cursor cursor = m_idToCursorMap.get(key); + if (cursor == null) { + cursor = new Cursor(Display.getDefault(), id); + m_idToCursorMap.put(key, cursor); + } + return cursor; + } + + /** + * Dispose all of the cached cursors. + */ + public static void disposeCursors() { + for (Cursor cursor : m_idToCursorMap.values()) { + cursor.dispose(); + } + m_idToCursorMap.clear(); + } + + //////////////////////////////////////////////////////////////////////////// + // + // General + // + //////////////////////////////////////////////////////////////////////////// + /** + * Dispose of cached objects and their underlying OS resources. This should only + * be called when the cached objects are no longer needed (e.g. on application + * shutdown). + */ + public static void dispose() { + disposeColors(); + disposeImages(); + disposeFonts(); + disposeCursors(); + } + + public static void report() { + System.out.println("Colormap : " + m_colorMap.size()); + System.out.println("DecoratedImageMap : " + m_decoratedImageMap.length); + System.out.println("Fontmap : " + m_fontMap.size()); + System.out.println("CursorMap : " + m_idToCursorMap.size()); + System.out.println("ImageMap : " + m_imageMap.size()); + } +}
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/package-info.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/package-info.java new file mode 100644 index 000000000..b90369b25 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/internal/util/package-info.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Provides some classes for internal use. + */ +package org.eclipse.tips.ui.internal.util;
\ No newline at end of file diff --git a/org.eclipse.tips.ui/src/org/eclipse/tips/ui/package-info.java b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/package-info.java new file mode 100644 index 000000000..73b68a021 --- /dev/null +++ b/org.eclipse.tips.ui/src/org/eclipse/tips/ui/package-info.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2018 Remain Software + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * wim.jongman@remainsoftware.com - initial API and implementation + *******************************************************************************/ +/** + * Provides tip UI classes. You should be able to reuse the TipComposite outside + * of the tips framework. + */ +package org.eclipse.tips.ui;
\ No newline at end of file @@ -65,5 +65,9 @@ <module>org.eclipse.ui.intro.quicklinks</module> <module>org.eclipse.ui.intro.quicklinks.examples</module> <module>org.eclipse.ui.intro.solstice.examples</module> + <module>org.eclipse.tips.core</module> + <module>org.eclipse.tips.ui</module> + <module>org.eclipse.tips.ide</module> + </modules> </project> |