| @@ -13,5 +13,6 @@ | |||||
| <attribute name="maven.pomderived" value="true"/> | <attribute name="maven.pomderived" value="true"/> | ||||
| </attributes> | </attributes> | ||||
| </classpathentry> | </classpathentry> | ||||
| <classpathentry kind="lib" path="swing2swt.jar"/> | |||||
| <classpathentry kind="output" path="target/classes"/> | <classpathentry kind="output" path="target/classes"/> | ||||
| </classpath> | </classpath> | ||||
| @@ -1,30 +1,10 @@ | |||||
| <?xml version="1.0" encoding="ASCII"?> | <?xml version="1.0" encoding="ASCII"?> | ||||
| <application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_Lw_ZsEqSEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.application"> | <application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_Lw_ZsEqSEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.application"> | ||||
| <children xsi:type="basic:TrimmedWindow" xmi:id="_QDxdgEqSEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.trimmedwindow.main" label="BGG Tool Another" width="1600" height="900"> | |||||
| <children xsi:type="basic:PartSashContainer" xmi:id="_B_h_UEqVEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.partsashcontainer.0"> | |||||
| <children xsi:type="basic:PartSashContainer" xmi:id="_tbnr0EqTEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.partsashcontainer.main" horizontal="true"> | |||||
| <children xsi:type="basic:PartSashContainer" xmi:id="_4NsHQEqTEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.partsashcontainer.left"> | |||||
| <children xsi:type="basic:PartStack" xmi:id="_7KNiwEqTEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.partstack.leftupper" containerData="800"> | |||||
| <children xsi:type="basic:Part" xmi:id="_9ocfwEqTEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.part.resultconfig" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.PreparePart" label="Prepare"/> | |||||
| </children> | |||||
| <children xsi:type="basic:PartStack" xmi:id="_0MbRQEqTEeqT5sxfmvJ5Tg" elementId="de.wt.bgg.ui.partstack.rightupper" containerData="800"> | |||||
| <children xsi:type="basic:Part" xmi:id="_-Mdy0EqTEeqT5sxfmvJ5Tg" elementId="de.wt.bgg.ui.part.gamesconfig" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.DownloadThingDetailsPart" label="Download details"/> | |||||
| </children> | |||||
| </children> | |||||
| <children xsi:type="basic:PartSashContainer" xmi:id="_AF1vQEqUEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.partsashcontainer.right"> | |||||
| <children xsi:type="basic:PartStack" xmi:id="_0OB_gJ2wEeqjssfAjxHZ-w" elementId="xyz.veronie.bgg.ui.partstack.leftlower" containerData="800"> | |||||
| <children xsi:type="basic:Part" xmi:id="_97XbwEqTEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.part.resulttable" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.BggResultPart" label="BGG Result"> | |||||
| <toolbar xmi:id="_ZZOF8J3AEeqjssfAjxHZ-w" elementId="xyz.veronie.bgg.ui.toolbar.0"> | |||||
| <children xsi:type="menu:DirectToolItem" xmi:id="_c42V4J29EeqjssfAjxHZ-w" elementId="xyz.veronie.bgg.ui.directtoolitem.saveResult" label="save result" iconURI="platform:/plugin/xyz.veronie.bgg.ui/icons/save-button.png" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.handlers.HandleSaveGamelist"/> | |||||
| <children xsi:type="menu:DirectToolItem" xmi:id="_VeUlQFZdEeu8-NdCRpPGXA" elementId="xyz.veronie.bgg.ui.directtoolitem.openlist" label="open list" iconURI="platform:/plugin/xyz.veronie.bgg.ui/icons/folder-symbol.png"/> | |||||
| </toolbar> | |||||
| </children> | |||||
| </children> | |||||
| <children xsi:type="basic:PartStack" xmi:id="_2M6HAJ2wEeqjssfAjxHZ-w" elementId="xyz.veronie.bgg.ui.rightlower" containerData="200"> | |||||
| <children xsi:type="basic:Part" xmi:id="_Ckm3wEqUEeqT5sxfmvJ5Tg" elementId="de.wt.bgg.ui.part.gamestable" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.ThingListPart" label="Games list"/> | |||||
| </children> | |||||
| </children> | |||||
| </children> | |||||
| <children xsi:type="basic:TrimmedWindow" xmi:id="_QDxdgEqSEeqT5sxfmvJ5Tg" elementId="xyz.veronie.bgg.ui.trimmedwindow.main" label="BGG Tool Another" width="700" height="700"> | |||||
| <children xsi:type="basic:PartStack" xmi:id="_uw_Z4F9REeuvNqpgCDWpdQ" elementId="xyz.veronie.bgg.ui.partstack.0"> | |||||
| <children xsi:type="basic:Part" xmi:id="_co2toF9CEeuvNqpgCDWpdQ" elementId="xyz.veronie.bgg.ui.part.batmain" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.BatMain" label="Home"/> | |||||
| <children xsi:type="basic:Part" xmi:id="_JsfvUF9YEeuvNqpgCDWpdQ" elementId="xyz.veronie.bgg.ui.part.fetch" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.FetchPart" label="Fetch"/> | |||||
| <children xsi:type="basic:Part" xmi:id="_ACADIF9cEeutIcDDGAEMFw" elementId="xyz.veronie.bgg.ui.part.prepare" contributionURI="bundleclass://xyz.veronie.bgg.ui/xyz.veronie.bgg.ui.parts.PreparePart" label="Prepare"/> | |||||
| </children> | </children> | ||||
| <mainMenu xmi:id="_wtXeQEs0EeqGDvPDavxXPQ" elementId="org.eclipse.ui.main.menu"/> | <mainMenu xmi:id="_wtXeQEs0EeqGDvPDavxXPQ" elementId="org.eclipse.ui.main.menu"/> | ||||
| <trimBars xmi:id="_I6MLEFv-EeqNgfoocONcgg" elementId="xyz.veronie.bgg.ui.trimbar.bottom" side="Bottom"> | <trimBars xmi:id="_I6MLEFv-EeqNgfoocONcgg" elementId="xyz.veronie.bgg.ui.trimbar.bottom" side="Bottom"> | ||||
| @@ -34,6 +14,7 @@ | |||||
| <children xsi:type="menu:ToolBar" xmi:id="_AX9yMIucEeqEpr8WQZMuMQ" elementId="xyz.veronie.bgg.ui.toolbar.testbar"/> | <children xsi:type="menu:ToolBar" xmi:id="_AX9yMIucEeqEpr8WQZMuMQ" elementId="xyz.veronie.bgg.ui.toolbar.testbar"/> | ||||
| </trimBars> | </trimBars> | ||||
| </children> | </children> | ||||
| <commands xmi:id="_lA5t8F9TEeuvNqpgCDWpdQ" elementId="xyz.veronie.bgg.ui.command.save" commandName="Save" description="save game list"/> | |||||
| <addons xmi:id="_Lw_ZsUqSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/> | <addons xmi:id="_Lw_ZsUqSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/> | ||||
| <addons xmi:id="_Lw_ZskqSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/> | <addons xmi:id="_Lw_ZskqSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/> | ||||
| <addons xmi:id="_Lw_Zs0qSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/> | <addons xmi:id="_Lw_Zs0qSEeqT5sxfmvJ5Tg" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/> | ||||
| @@ -3,6 +3,8 @@ Bundle-ManifestVersion: 2 | |||||
| Bundle-Name: Secondtry | Bundle-Name: Secondtry | ||||
| Bundle-SymbolicName: xyz.veronie.bgg.ui;singleton:=true | Bundle-SymbolicName: xyz.veronie.bgg.ui;singleton:=true | ||||
| Bundle-Version: 1.0.0.qualifier | Bundle-Version: 1.0.0.qualifier | ||||
| Bundle-ClassPath: lib/sqlite-jdbc-3.34.0.jar, | |||||
| swing2swt.jar | |||||
| Require-Bundle: org.eclipse.core.runtime, | Require-Bundle: org.eclipse.core.runtime, | ||||
| org.eclipse.swt, | org.eclipse.swt, | ||||
| org.eclipse.e4.core.di, | org.eclipse.e4.core.di, | ||||
| @@ -15,9 +17,9 @@ Require-Bundle: org.eclipse.core.runtime, | |||||
| org.eclipse.osgi.services, | org.eclipse.osgi.services, | ||||
| javax.inject, | javax.inject, | ||||
| org.eclipse.e4.ui.model.workbench | org.eclipse.e4.ui.model.workbench | ||||
| Automatic-Module-Name: de.wt.secondtry | |||||
| Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | ||||
| Import-Package: javax.inject;version="1.0.0", | |||||
| Import-Package: javax.annotation;version="1.0.0";resolution:=optional, | |||||
| javax.inject;version="1.0.0", | |||||
| org.eclipse.e4.ui.model.application.descriptor.basic, | org.eclipse.e4.ui.model.application.descriptor.basic, | ||||
| org.eclipse.e4.ui.model.application.ui.basic | org.eclipse.e4.ui.model.application.ui.basic | ||||
| Bundle-ClassPath: lib/sqlite-jdbc-3.34.0.jar | |||||
| Automatic-Module-Name: de.wt.secondtry | |||||
| @@ -0,0 +1,438 @@ | |||||
| /******************************************************************************* | |||||
| * Copyright (c) 2011 Google, Inc. and others | |||||
| * 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 | |||||
| * Wim Jongman - 1.8 and higher compliance | |||||
| *******************************************************************************/ | |||||
| package org.eclipse.wb.swt; | |||||
| 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.Iterator; | |||||
| 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.ImageData; | |||||
| import org.eclipse.swt.graphics.ImageDataProvider; | |||||
| 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. | |||||
| * | |||||
| * This class is created automatically when you fiddle around with images and | |||||
| * colors in WB. You might want to prevent your application from using this | |||||
| * class and provide your own more effective means of resource caching. | |||||
| * | |||||
| * Even though this class can be used to manage these resources, if they are | |||||
| * here for the duration of the application and not used then you still have an | |||||
| * effective resource leak. | |||||
| * | |||||
| * 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. | |||||
| * | |||||
| * This class may be freely distributed as part of any application or plugin. | |||||
| * <p> | |||||
| * | |||||
| * @author scheglov_ke | |||||
| * @author Dan Rubel | |||||
| * @author Wim Jongman | |||||
| */ | |||||
| public class ResourceManager extends SWTResourceManager { | |||||
| /** | |||||
| * The map where we store our images. | |||||
| */ | |||||
| 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(getUnzoomedImageDataProvider(decorator.getImageData()) , 0, 0); | |||||
| } else if (corner == TOP_RIGHT) { | |||||
| drawImage(getUnzoomedImageDataProvider(decorator.getImageData()), bib.width - dib.width, 0); | |||||
| } else if (corner == BOTTOM_LEFT) { | |||||
| drawImage(getUnzoomedImageDataProvider(decorator.getImageData()), 0, bib.height - dib.height); | |||||
| } else if (corner == BOTTOM_RIGHT) { | |||||
| drawImage(getUnzoomedImageDataProvider(decorator.getImageData()), bib.width - dib.width, bib.height - dib.height); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| protected Point getSize() { | |||||
| return baseImageSize; | |||||
| } | |||||
| }; | |||||
| // | |||||
| result = compositImageDesc.createImage(); | |||||
| decoratedMap.put(decorator, result); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private static ImageDataProvider getUnzoomedImageDataProvider(ImageData imageData) { | |||||
| return zoom -> zoom == 100 ? imageData : null; | |||||
| } | |||||
| /** | |||||
| * Dispose all of the cached images. | |||||
| */ | |||||
| public static void disposeImages() { | |||||
| SWTResourceManager.disposeImages(); | |||||
| // dispose ImageDescriptor images | |||||
| { | |||||
| for (Iterator<Image> I = m_descriptorImageMap.values().iterator(); I.hasNext();) { | |||||
| I.next().dispose(); | |||||
| } | |||||
| m_descriptorImageMap.clear(); | |||||
| } | |||||
| // dispose decorated images | |||||
| for (int i = 0; i < m_decoratedImageMap.length; i++) { | |||||
| Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i]; | |||||
| 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 (Iterator<Image> I = m_URLImageMap.values().iterator(); I.hasNext();) { | |||||
| I.next().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) { | |||||
| InputStream stream = url.openStream(); | |||||
| try { | |||||
| image = getImage(stream); | |||||
| m_URLImageMap.put(key, image); | |||||
| } finally { | |||||
| stream.close(); | |||||
| } | |||||
| } | |||||
| 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(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,447 @@ | |||||
| /******************************************************************************* | |||||
| * Copyright (c) 2011 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.wb.swt; | |||||
| 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 (int i = 0; i < m_decoratedImageMap.length; i++) { | |||||
| Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i]; | |||||
| 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(); | |||||
| } | |||||
| } | |||||
| @@ -1,70 +1,93 @@ | |||||
| package xyz.veronie.bgg.ui.dialogs; | package xyz.veronie.bgg.ui.dialogs; | ||||
| import static org.eclipse.jface.widgets.WidgetFactory.text; | |||||
| import org.eclipse.jface.dialogs.Dialog; | import org.eclipse.jface.dialogs.Dialog; | ||||
| import org.eclipse.jface.dialogs.IDialogConstants; | |||||
| import org.eclipse.swt.SWT; | import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.FocusEvent; | |||||
| import org.eclipse.swt.events.FocusListener; | |||||
| import org.eclipse.swt.events.ModifyEvent; | |||||
| import org.eclipse.swt.events.ModifyListener; | |||||
| import org.eclipse.swt.graphics.Point; | import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.layout.GridData; | import org.eclipse.swt.layout.GridData; | ||||
| import org.eclipse.swt.layout.GridLayout; | import org.eclipse.swt.layout.GridLayout; | ||||
| import org.eclipse.swt.widgets.Composite; | import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Control; | import org.eclipse.swt.widgets.Control; | ||||
| import org.eclipse.swt.widgets.Label; | |||||
| import org.eclipse.swt.widgets.Shell; | import org.eclipse.swt.widgets.Shell; | ||||
| import org.eclipse.swt.widgets.Text; | import org.eclipse.swt.widgets.Text; | ||||
| import org.eclipse.wb.swt.SWTResourceManager; | |||||
| import xyz.veronie.bgg.ui.helpers.BatColors; | |||||
| public class SaveGameListDialog extends Dialog { | public class SaveGameListDialog extends Dialog { | ||||
| private Text textField; | |||||
| private String entryString; | private String entryString; | ||||
| /** | |||||
| * Create the dialog. | |||||
| * @param parentShell | |||||
| */ | |||||
| public SaveGameListDialog(Shell parentShell) { | public SaveGameListDialog(Shell parentShell) { | ||||
| super(parentShell); | |||||
| } | |||||
| @Override | |||||
| protected Control createDialogArea(Composite parent) { | |||||
| Composite container = (Composite) super.createDialogArea(parent); | |||||
| GridLayout layout = new GridLayout(1, false); | |||||
| layout.marginLeft = 16; | |||||
| layout.marginTop = 16; | |||||
| layout.marginRight = 16; | |||||
| layout.marginBottom = 16; | |||||
| container.setLayout(layout); | |||||
| super(parentShell); | |||||
| setShellStyle(SWT.APPLICATION_MODAL); | |||||
| } | |||||
| Text text = text(SWT.BORDER).message("Enter game list name") | |||||
| .limitTo(255) | |||||
| .layoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false)) | |||||
| .create(container); | |||||
| /** | |||||
| * Create contents of the dialog. | |||||
| * @param parent | |||||
| */ | |||||
| @Override | |||||
| protected Control createDialogArea(Composite parent) { | |||||
| parent.setBackground(BatColors.getBackgroundColor()); | |||||
| Composite container = (Composite) super.createDialogArea(parent); | |||||
| container.setFont(SWTResourceManager.getFont("Segoe UI", 11, SWT.NORMAL)); | |||||
| container.setBackground(BatColors.getBackgroundColor()); | |||||
| GridLayout gl_container = new GridLayout(1, false); | |||||
| gl_container.verticalSpacing = 24; | |||||
| gl_container.marginWidth = 24; | |||||
| gl_container.marginTop = 24; | |||||
| gl_container.marginRight = 24; | |||||
| gl_container.marginLeft = 24; | |||||
| gl_container.marginHeight = 24; | |||||
| gl_container.marginBottom = 24; | |||||
| gl_container.horizontalSpacing = 24; | |||||
| container.setLayout(gl_container); | |||||
| Label lblEnterAName = new Label(container, SWT.NONE); | |||||
| lblEnterAName.setFont(SWTResourceManager.getFont("Segoe UI", 11, SWT.NORMAL)); | |||||
| lblEnterAName.setText("Enter a name for the game list:"); | |||||
| textField = new Text(container, SWT.BORDER); | |||||
| textField.addModifyListener(new ModifyListener() { | |||||
| public void modifyText(ModifyEvent e) { | |||||
| Text t = (Text) e.widget; | |||||
| entryString = t.getText(); | |||||
| } | |||||
| }); | |||||
| textField.setFont(SWTResourceManager.getFont("Segoe UI", 11, SWT.NORMAL)); | |||||
| textField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); | |||||
| return container; | |||||
| } | |||||
| FocusListener focusListener = new FocusListener() { | |||||
| public void focusGained(FocusEvent e) { | |||||
| } | |||||
| /** | |||||
| * Create contents of the button bar. | |||||
| * @param parent | |||||
| */ | |||||
| @Override | |||||
| protected void createButtonsForButtonBar(Composite parent) { | |||||
| parent.setBackground(BatColors.getBackgroundColor()); | |||||
| createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); | |||||
| createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); | |||||
| } | |||||
| public void focusLost(FocusEvent e) { | |||||
| Text t = (Text) e.widget; | |||||
| entryString = t.getText(); | |||||
| } | |||||
| }; | |||||
| text.addFocusListener(focusListener); | |||||
| return container; | |||||
| } | |||||
| // overriding this methods allows you to set the | |||||
| // title of the custom dialog | |||||
| @Override | |||||
| protected void configureShell(Shell newShell) { | |||||
| super.configureShell(newShell); | |||||
| newShell.setText("Enter game list name"); | |||||
| } | |||||
| /** | |||||
| * Return the initial size of the dialog. | |||||
| */ | |||||
| @Override | |||||
| protected Point getInitialSize() { | |||||
| return new Point(450, 300); | |||||
| } | |||||
| @Override | |||||
| protected Point getInitialSize() { | |||||
| return new Point(450, 300); | |||||
| } | |||||
| public String getEntryText() { | public String getEntryText() { | ||||
| return entryString; | return entryString; | ||||
| @@ -1,8 +1,6 @@ | |||||
| package xyz.veronie.bgg.ui.handlers; | package xyz.veronie.bgg.ui.handlers; | ||||
| import javax.inject.Inject; | |||||
| import org.eclipse.e4.core.di.annotations.CanExecute; | import org.eclipse.e4.core.di.annotations.CanExecute; | ||||
| import org.eclipse.e4.core.di.annotations.Execute; | import org.eclipse.e4.core.di.annotations.Execute; | ||||
| import org.eclipse.jface.dialogs.Dialog; | import org.eclipse.jface.dialogs.Dialog; | ||||
| @@ -15,9 +13,14 @@ import xyz.veronie.bgg.ui.dialogs.SaveGameListDialog; | |||||
| public class HandleSaveGamelist { | public class HandleSaveGamelist { | ||||
| @Inject | |||||
| // @Inject | |||||
| ThingProvider thingProvider; | ThingProvider thingProvider; | ||||
| public HandleSaveGamelist(ThingProvider thingProvider) { | |||||
| this.thingProvider = thingProvider; | |||||
| } | |||||
| @Execute | @Execute | ||||
| public void execute(Shell shell) { | public void execute(Shell shell) { | ||||
| @@ -0,0 +1,16 @@ | |||||
| package xyz.veronie.bgg.ui.helpers; | |||||
| import org.eclipse.swt.graphics.Color; | |||||
| import org.eclipse.wb.swt.SWTResourceManager; | |||||
| public class BatColors { | |||||
| public static Color getBackgroundColor() { | |||||
| return SWTResourceManager.getColor(155,142,237); | |||||
| } | |||||
| public static Color getButtonBgColor() { | |||||
| return SWTResourceManager.getColor(255,81,0); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| package xyz.veronie.bgg.ui.helpers; | |||||
| import org.eclipse.swt.layout.GridLayout; | |||||
| public class BatLayouts { | |||||
| public static void applyStandardSpacing(GridLayout gl) { | |||||
| gl.horizontalSpacing = 8; | |||||
| gl.verticalSpacing = 24; | |||||
| gl.marginWidth = 8; | |||||
| gl.marginTop = 8; | |||||
| gl.marginRight = 8; | |||||
| gl.marginLeft = 8; | |||||
| gl.marginHeight = 8; | |||||
| gl.marginBottom = 8; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,274 @@ | |||||
| package xyz.veronie.bgg.ui.parts; | |||||
| import java.util.List; | |||||
| import javax.annotation.PostConstruct; | |||||
| import javax.inject.Inject; | |||||
| import org.eclipse.e4.core.di.annotations.Optional; | |||||
| import org.eclipse.e4.core.services.events.IEventBroker; | |||||
| import org.eclipse.e4.ui.di.UIEventTopic; | |||||
| import org.eclipse.e4.ui.model.application.MApplication; | |||||
| import org.eclipse.e4.ui.model.application.ui.basic.MPart; | |||||
| import org.eclipse.e4.ui.workbench.modeling.EModelService; | |||||
| import org.eclipse.e4.ui.workbench.modeling.EPartService; | |||||
| import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState; | |||||
| import org.eclipse.jface.viewers.ArrayContentProvider; | |||||
| import org.eclipse.jface.viewers.ColumnLabelProvider; | |||||
| import org.eclipse.jface.viewers.ISelectionChangedListener; | |||||
| import org.eclipse.jface.viewers.IStructuredSelection; | |||||
| import org.eclipse.jface.viewers.SelectionChangedEvent; | |||||
| import org.eclipse.jface.viewers.TableViewer; | |||||
| import org.eclipse.jface.viewers.TableViewerColumn; | |||||
| import org.eclipse.swt.SWT; | |||||
| import org.eclipse.swt.events.MouseAdapter; | |||||
| import org.eclipse.swt.events.MouseEvent; | |||||
| import org.eclipse.swt.graphics.Color; | |||||
| import org.eclipse.swt.graphics.Image; | |||||
| 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.Label; | |||||
| import org.eclipse.swt.widgets.Table; | |||||
| import org.eclipse.swt.widgets.TableColumn; | |||||
| import org.eclipse.wb.swt.ResourceManager; | |||||
| import org.eclipse.wb.swt.SWTResourceManager; | |||||
| import xyz.veronie.bgg.result.Thing; | |||||
| import xyz.veronie.bgg.result.ThingProvider; | |||||
| import xyz.veronie.bgg.types.EventConstants; | |||||
| import xyz.veronie.bgg.ui.handlers.HandleSaveGamelist; | |||||
| import xyz.veronie.bgg.ui.helpers.BatColors; | |||||
| import xyz.veronie.bgg.ui.helpers.BatLayouts; | |||||
| public class BatMain { | |||||
| private Table tableGameList; | |||||
| private TableViewer tableViewer; | |||||
| @Inject | |||||
| private ThingProvider thingProvider; | |||||
| @Inject | |||||
| private IEventBroker eventBroker; | |||||
| @Inject | |||||
| public BatMain() { | |||||
| } | |||||
| @PostConstruct | |||||
| public void postConstruct(Composite parent, MApplication application, EPartService partService, EModelService modelService) { | |||||
| Color bgColor = BatColors.getBackgroundColor(); | |||||
| parent.setBackground(bgColor); | |||||
| GridLayout gl_parent = new GridLayout(1, false); | |||||
| gl_parent.horizontalSpacing = 0; | |||||
| gl_parent.verticalSpacing = 0; | |||||
| gl_parent.marginWidth = 0; | |||||
| gl_parent.marginHeight = 0; | |||||
| parent.setLayout(gl_parent); | |||||
| Composite main = new Composite(parent, SWT.NONE); | |||||
| GridData gd_main = new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1); | |||||
| gd_main.minimumHeight = 192; | |||||
| gd_main.minimumWidth = 348; | |||||
| main.setLayoutData(gd_main); | |||||
| main.setBackground(bgColor); | |||||
| GridLayout gl_main = new GridLayout(1, false); | |||||
| gl_main.verticalSpacing = 24; | |||||
| BatLayouts.applyStandardSpacing(gl_main); | |||||
| main.setLayout(gl_main); | |||||
| Composite buttonRow = new Composite(main, SWT.NONE); | |||||
| buttonRow.setBackground(bgColor); | |||||
| GridLayout gl_buttonRow = new GridLayout(5, false); | |||||
| gl_buttonRow.verticalSpacing = 8; | |||||
| gl_buttonRow.marginWidth = 0; | |||||
| gl_buttonRow.marginHeight = 8; | |||||
| gl_buttonRow.horizontalSpacing = 8; | |||||
| BatLayouts.applyStandardSpacing(gl_buttonRow); | |||||
| buttonRow.setLayout(gl_buttonRow); | |||||
| buttonRow.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 1, 1)); | |||||
| Button btnFetch = new Button(buttonRow, SWT.NONE); | |||||
| btnFetch.addMouseListener(new MouseAdapter() { | |||||
| @Override | |||||
| public void mouseUp(MouseEvent e) { | |||||
| List<MPart> parts = modelService.findElements(application, "xyz.veronie.bgg.ui.part.fetch", MPart.class); | |||||
| if(parts != null && parts.size() >= 1) { | |||||
| MPart fetchPart = parts.get(0); | |||||
| partService.showPart(fetchPart, PartState.CREATE); | |||||
| partService.showPart(fetchPart, PartState.ACTIVATE); | |||||
| } | |||||
| } | |||||
| }); | |||||
| btnFetch.setToolTipText("Fetch games from BGG"); | |||||
| btnFetch.setForeground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| btnFetch.setBackground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| btnFetch.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_Download_60x60.png")); | |||||
| Button btnSave = new Button(buttonRow, SWT.NONE); | |||||
| btnSave.addMouseListener(new MouseAdapter() { | |||||
| @Override | |||||
| public void mouseUp(MouseEvent e) { | |||||
| // TODO: find a loose coupling instead. Where is EHandlerService??? | |||||
| HandleSaveGamelist handleSaveGameList = new HandleSaveGamelist(thingProvider); | |||||
| if(handleSaveGameList.canExecute()) { | |||||
| handleSaveGameList.execute(parent.getShell()); | |||||
| } | |||||
| } | |||||
| }); | |||||
| btnSave.setToolTipText("Save list of games"); | |||||
| btnSave.setBackground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| btnSave.setForeground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| btnSave.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_Save_60x60.png")); | |||||
| Button btnLoad = new Button(buttonRow, SWT.NONE); | |||||
| btnLoad.setBackground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| btnLoad.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_open_60x60.png")); | |||||
| btnLoad.setToolTipText("Load list of games"); | |||||
| Button btnUndo = new Button(buttonRow, SWT.NONE); | |||||
| btnUndo.setToolTipText("Undo game list operation"); | |||||
| btnUndo.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_Undo_60x60.png")); | |||||
| btnUndo.setBackground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| Button btnExport = new Button(buttonRow, SWT.NONE); | |||||
| btnExport.setBackground(SWTResourceManager.getColor(SWT.COLOR_TRANSPARENT)); | |||||
| btnExport.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/export_nandeck_60x60.png")); | |||||
| btnExport.setToolTipText("Export for nanDeck"); | |||||
| tableViewer = new TableViewer(main, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI); | |||||
| tableGameList = tableViewer.getTable(); | |||||
| tableGameList.setLinesVisible(true); | |||||
| tableGameList.setHeaderVisible(true); | |||||
| GridData gd_tableGameList = new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1); | |||||
| gd_tableGameList.heightHint = 466; | |||||
| tableGameList.setLayoutData(gd_tableGameList); | |||||
| createColumns(tableViewer); | |||||
| tableViewer.setContentProvider(new ArrayContentProvider()); | |||||
| // Get the content for the viewer, setInput will call getElements in the | |||||
| // contentProvider | |||||
| tableViewer.setInput(thingProvider.getThings()); | |||||
| // make the selection available to other views | |||||
| // TODO: getSite().setSelectionProvider(viewer); | |||||
| // Set the sorter for the table | |||||
| tableViewer.addSelectionChangedListener(new ISelectionChangedListener() { | |||||
| @Override | |||||
| public void selectionChanged(SelectionChangedEvent event) { | |||||
| IStructuredSelection selection = tableViewer.getStructuredSelection(); | |||||
| Thing thing = (Thing)selection.getFirstElement(); | |||||
| eventBroker.send(EventConstants.TOPIC_THING_SELECTION, thing); | |||||
| } | |||||
| }); | |||||
| Composite statusRow = new Composite(main, SWT.NONE); | |||||
| statusRow.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 1, 1)); | |||||
| GridLayout gl_statusRow = new GridLayout(1, false); | |||||
| gl_statusRow.verticalSpacing = 8; | |||||
| gl_statusRow.marginWidth = 8; | |||||
| gl_statusRow.marginHeight = 8; | |||||
| gl_statusRow.horizontalSpacing = 8; | |||||
| BatLayouts.applyStandardSpacing(gl_statusRow); | |||||
| statusRow.setLayout(gl_statusRow); | |||||
| Label lblResultStatus = new Label(statusRow, SWT.NONE); | |||||
| lblResultStatus.setText("0 items"); | |||||
| } | |||||
| public TableViewer getViewer() { | |||||
| return tableViewer; | |||||
| } | |||||
| // This will create the columns for the table | |||||
| private void createColumns(final TableViewer viewer) { | |||||
| // https://stackoverflow.com/questions/12641354/putting-an-image-in-to-a-jface-table-cell-is-causing-gap-for-image-to-appear-in | |||||
| TableViewerColumn col = createTableViewerColumn(Thing.IdHeader, 250, 0); | |||||
| col.setLabelProvider(new ColumnLabelProvider() { | |||||
| @Override | |||||
| public String getText(Object element) { | |||||
| Thing t = (Thing) element; | |||||
| return t.getField((int)col.getColumn().getData()); | |||||
| } | |||||
| }); | |||||
| TableViewerColumn col2 = createTableViewerColumn(Thing.ThumbHeader, 150, 1); | |||||
| col2.setLabelProvider(new ColumnLabelProvider() { | |||||
| @Override | |||||
| public Image getImage(Object element) { | |||||
| Thing t = (Thing) element; | |||||
| Image img = t.getThumbnail(); | |||||
| return img; | |||||
| } | |||||
| @Override | |||||
| public String getText(Object element) { | |||||
| return ""; | |||||
| } | |||||
| }); | |||||
| TableViewerColumn col3 = createTableViewerColumn(Thing.NameHeader, 400, 2); | |||||
| col3.setLabelProvider(new ColumnLabelProvider() { | |||||
| @Override | |||||
| public String getText(Object element) { | |||||
| Thing t = (Thing) element; | |||||
| return t.getField((int)col3.getColumn().getData()); | |||||
| } | |||||
| }); | |||||
| } | |||||
| private TableViewerColumn createTableViewerColumn(String title, int bound, final int colNumber) { | |||||
| final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, | |||||
| SWT.NONE); | |||||
| final TableColumn column = viewerColumn.getColumn(); | |||||
| column.setText(title); | |||||
| column.setWidth(bound); | |||||
| column.setAlignment(SWT.LEFT); | |||||
| column.setResizable(true); | |||||
| column.setMoveable(true); | |||||
| column.setData(colNumber); | |||||
| return viewerColumn; | |||||
| } | |||||
| /** | |||||
| * Passing the focus request to the viewer's control. | |||||
| */ | |||||
| public void setFocus() { | |||||
| tableViewer.getControl().setFocus(); | |||||
| } | |||||
| @Inject | |||||
| @Optional | |||||
| private void subscribeTopicResultChanged | |||||
| (@UIEventTopic(EventConstants.TOPIC_RESULT_CHANGED) | |||||
| String empty) { | |||||
| System.out.println("TOPIC_RESULT_CHANGED"); | |||||
| List<Thing> things = thingProvider.getThings(); | |||||
| tableViewer.setInput(things); | |||||
| tableViewer.refresh(true); | |||||
| // if(things != null) { | |||||
| // statsLabel.setText(Integer.toString(things.size()) + " items"); | |||||
| // statsLabel.redraw(); | |||||
| // } | |||||
| } | |||||
| } | |||||
| @@ -33,33 +33,6 @@ import xyz.veronie.bgg.result.Thing; | |||||
| import xyz.veronie.bgg.result.ThingProvider; | import xyz.veronie.bgg.result.ThingProvider; | ||||
| import xyz.veronie.bgg.types.EventConstants; | import xyz.veronie.bgg.types.EventConstants; | ||||
| abstract class CenterImageLabelProvider extends OwnerDrawLabelProvider { | |||||
| protected void measure(Event event, Object element) { | |||||
| } | |||||
| protected void paint(Event event, Object element) { | |||||
| Image img = getImage(element); | |||||
| if (img != null) { | |||||
| Rectangle bounds = ((TableItem) event.item).getBounds(event.index); | |||||
| Rectangle imgBounds = img.getBounds(); | |||||
| bounds.width /= 2; | |||||
| bounds.width -= imgBounds.width / 2; | |||||
| bounds.height /= 2; | |||||
| bounds.height -= imgBounds.height / 2; | |||||
| int x = bounds.width > 0 ? bounds.x + bounds.width : bounds.x; | |||||
| int y = bounds.height > 0 ? bounds.y + bounds.height : bounds.y; | |||||
| event.gc.drawImage(img, x, y); | |||||
| } | |||||
| } | |||||
| protected abstract Image getImage(Object element); | |||||
| }; | |||||
| public class BggResultPart { | public class BggResultPart { | ||||
| private TableViewer viewer; | private TableViewer viewer; | ||||
| @@ -72,7 +45,7 @@ public class BggResultPart { | |||||
| private IEventBroker eventBroker; | private IEventBroker eventBroker; | ||||
| @PostConstruct | @PostConstruct | ||||
| public void createControls(Composite parent) { | |||||
| public void createContents(Composite parent) { | |||||
| Composite main = new Composite(parent, SWT.FILL); | Composite main = new Composite(parent, SWT.FILL); | ||||
| main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); | main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); | ||||
| @@ -0,0 +1,298 @@ | |||||
| package xyz.veronie.bgg.ui.parts; | |||||
| import java.util.ArrayList; | |||||
| import javax.annotation.PostConstruct; | |||||
| import javax.inject.Inject; | |||||
| import org.eclipse.e4.core.services.events.IEventBroker; | |||||
| import org.eclipse.jface.dialogs.MessageDialog; | |||||
| import org.eclipse.jface.viewers.IStructuredSelection; | |||||
| import org.eclipse.swt.SWT; | |||||
| import org.eclipse.swt.events.MouseAdapter; | |||||
| import org.eclipse.swt.events.MouseEvent; | |||||
| import org.eclipse.swt.events.SelectionEvent; | |||||
| 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.Group; | |||||
| import org.eclipse.wb.swt.ResourceManager; | |||||
| import xyz.veronie.bgg.result.BggApi; | |||||
| import xyz.veronie.bgg.result.ResultConfig; | |||||
| import xyz.veronie.bgg.result.ResultConfigManager; | |||||
| import xyz.veronie.bgg.result.Thing; | |||||
| import xyz.veronie.bgg.result.ThingProvider; | |||||
| import xyz.veronie.bgg.types.EventConstants; | |||||
| import xyz.veronie.bgg.types.SourceFilter; | |||||
| import xyz.veronie.bgg.ui.filters.BggUserSourceFilter; | |||||
| import xyz.veronie.bgg.ui.filters.FamilySourceFilter; | |||||
| import xyz.veronie.bgg.ui.filters.GeeklistSourceFilter; | |||||
| import xyz.veronie.bgg.ui.helpers.BatColors; | |||||
| import xyz.veronie.bgg.ui.helpers.BatLayouts; | |||||
| import org.eclipse.swt.widgets.Label; | |||||
| public class FetchPart { | |||||
| @Inject | |||||
| private ResultConfigManager configManager; | |||||
| // inject all source filter composites | |||||
| @Inject private BggUserSourceFilter bggUserSourceFilter; | |||||
| @Inject private GeeklistSourceFilter geeklistSourceFilter; | |||||
| @Inject private FamilySourceFilter familySourceFilter; | |||||
| @Inject | |||||
| private IEventBroker eventBroker; | |||||
| @Inject | |||||
| private ThingProvider thingProvider; | |||||
| @Inject | |||||
| private BggApi bggApi; | |||||
| private Button btnBggUser; | |||||
| private Button btnFamily; | |||||
| private Button btnGeeklist; | |||||
| private SourceFilter source; | |||||
| private Composite main; | |||||
| private Group filterGroup; | |||||
| @Inject | |||||
| public FetchPart() { | |||||
| } | |||||
| @PostConstruct | |||||
| public void postConstruct(Composite parent) { | |||||
| parent.setBackground(BatColors.getBackgroundColor()); | |||||
| parent.setLayout(new GridLayout(1, false)); | |||||
| main = new Composite(parent, SWT.NONE); | |||||
| GridLayout gl_main = new GridLayout(1, false); | |||||
| BatLayouts.applyStandardSpacing(gl_main); | |||||
| main.setLayout(gl_main); | |||||
| main.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1)); | |||||
| Composite buttonRow = new Composite(main, SWT.NONE); | |||||
| buttonRow.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); | |||||
| GridLayout gl_buttonRow = new GridLayout(3, false); | |||||
| BatLayouts.applyStandardSpacing(gl_main); | |||||
| buttonRow.setLayout(gl_buttonRow); | |||||
| btnBggUser = new Button(buttonRow, SWT.NONE); | |||||
| btnBggUser.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_Meeple_60x60.png")); | |||||
| btnFamily = new Button(buttonRow, SWT.NONE); | |||||
| btnFamily.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_Family_60x60.png")); | |||||
| btnGeeklist = new Button(buttonRow, SWT.NONE); | |||||
| btnGeeklist.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/noun_List_60x60.png")); | |||||
| btnBggUser.addMouseListener(new MouseAdapter() { | |||||
| @Override | |||||
| public void mouseUp(MouseEvent e) { | |||||
| selectFilter(SourceFilter.BGG_USER); | |||||
| } | |||||
| }); | |||||
| btnFamily.addMouseListener(new MouseAdapter() { | |||||
| @Override | |||||
| public void mouseUp(MouseEvent e) { | |||||
| selectFilter(SourceFilter.FAMILY); | |||||
| } | |||||
| }); | |||||
| btnGeeklist.addMouseListener(new MouseAdapter() { | |||||
| @Override | |||||
| public void mouseUp(MouseEvent e) { | |||||
| selectFilter(SourceFilter.GEEKLIST); | |||||
| } | |||||
| }); | |||||
| Composite centerComposite = new Composite(main, SWT.NONE); | |||||
| centerComposite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1)); | |||||
| GridLayout gl_centerComposite = new GridLayout(1, false); | |||||
| BatLayouts.applyStandardSpacing(gl_centerComposite); | |||||
| centerComposite.setLayout(gl_centerComposite); | |||||
| filterGroup = new Group(centerComposite, SWT.NONE); | |||||
| filterGroup.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true, 1, 1)); | |||||
| filterGroup.setLayout(new GridLayout(1, false)); | |||||
| Composite applyComposite = new Composite(main, SWT.NONE); | |||||
| applyComposite.setLayout(new GridLayout(5, false)); | |||||
| applyComposite.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 1, 1)); | |||||
| Button btnOnlyNew = new Button(applyComposite, SWT.NONE); | |||||
| btnOnlyNew.addMouseListener(new MouseAdapter() { | |||||
| @Override | |||||
| public void mouseUp(MouseEvent e) { | |||||
| } | |||||
| }); | |||||
| btnOnlyNew.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/only_new_60x60.png")); | |||||
| btnOnlyNew.setToolTipText("Keep only new"); | |||||
| Button btnReplace = new Button(applyComposite, SWT.NONE); | |||||
| btnReplace.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/result_replace_60x60.png")); | |||||
| btnReplace.setToolTipText("Replace"); | |||||
| Button btnAdd = new Button(applyComposite, SWT.NONE); | |||||
| btnAdd.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/result_add_60x60.png")); | |||||
| btnAdd.setToolTipText("Add"); | |||||
| Button btnSubtract = new Button(applyComposite, SWT.NONE); | |||||
| btnSubtract.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/result_subtract_60x60.png")); | |||||
| btnSubtract.setToolTipText("Subtract"); | |||||
| Button btnIntersect = new Button(applyComposite, SWT.NONE); | |||||
| btnIntersect.setImage(ResourceManager.getPluginImage("xyz.veronie.bgg.ui", "icons/result_intersect_60x60.png")); | |||||
| btnIntersect.setToolTipText("Intersect"); | |||||
| // init filter using config manager | |||||
| source = configManager.getResultConfig().source; | |||||
| selectFilter(source); | |||||
| showFilter(filterGroup, source); | |||||
| } | |||||
| private void selectFilter(SourceFilter source) { | |||||
| switch(source) { | |||||
| default: | |||||
| case BGG_USER: | |||||
| btnBggUser.setFocus(); | |||||
| btnBggUser.setBackground(BatColors.getButtonBgColor()); | |||||
| btnFamily.setBackground(null); | |||||
| btnGeeklist.setBackground(null); | |||||
| break; | |||||
| case FAMILY: | |||||
| btnBggUser.setFocus(); | |||||
| btnBggUser.setBackground(null); | |||||
| btnFamily.setBackground(BatColors.getButtonBgColor()); | |||||
| btnGeeklist.setBackground(null); | |||||
| break; | |||||
| case GEEKLIST: | |||||
| btnGeeklist.setFocus(); | |||||
| btnBggUser.setBackground(null); | |||||
| btnFamily.setBackground(null); | |||||
| btnGeeklist.setBackground(BatColors.getButtonBgColor()); | |||||
| break; | |||||
| } | |||||
| showFilter(filterGroup, source); | |||||
| eventBroker.send(EventConstants.TOPIC_ACTION_CHANGED, source); | |||||
| } | |||||
| /// show different filter controls depending on selection in cbSource ComboViewer | |||||
| private void showFilter(Composite parent, SourceFilter source) { | |||||
| // clean up | |||||
| for(Control child : parent.getChildren()) { | |||||
| child.dispose(); | |||||
| } | |||||
| // create a new filter area based on selection: | |||||
| switch(source) { | |||||
| default: | |||||
| case BGG_USER: | |||||
| System.out.println("construct " + source); | |||||
| bggUserSourceFilter.create(parent, SWT.FILL); | |||||
| break; | |||||
| case GEEKLIST: | |||||
| System.out.println("construct " + source); | |||||
| geeklistSourceFilter.create(parent, SWT.FILL); | |||||
| break; | |||||
| case FAMILY: | |||||
| System.out.println("construct " + source); | |||||
| familySourceFilter.create(parent, SWT.FILL); | |||||
| break; | |||||
| } | |||||
| main.layout(true, true); | |||||
| } | |||||
| private void checkEntry() { | |||||
| ResultConfig resultConfig = configManager.getResultConfig(); | |||||
| if(source == SourceFilter.BGG_USER) { | |||||
| String user = resultConfig.user; | |||||
| if(user == null || user.isEmpty()) { | |||||
| MessageDialog.openError(main.getShell(), "", "Please enter a user name."); | |||||
| return; | |||||
| } else { | |||||
| eventBroker.send(EventConstants.TOPIC_STATUS, "Fetching " + source.toString() + " '" + user + "'..."); | |||||
| try { | |||||
| ArrayList<Thing> things = bggApi.getThingsForUser(user); | |||||
| useThingsOnResult(things); | |||||
| } | |||||
| catch(IllegalArgumentException ex) { | |||||
| MessageDialog.openError(main.getShell(), "", ex.getMessage()); | |||||
| } | |||||
| } | |||||
| } else if(source == SourceFilter.GEEKLIST) { | |||||
| Integer geeklistId = resultConfig.geeklistId; | |||||
| if(geeklistId == null) { | |||||
| MessageDialog.openError(main.getShell(), "", "Please enter a geeklist id."); | |||||
| return; | |||||
| } else { | |||||
| eventBroker.send(EventConstants.TOPIC_STATUS, "Fetching for geeklist id '" + geeklistId + "'"); | |||||
| try { | |||||
| ArrayList<Thing> things = bggApi.getThingsForGeeklist(geeklistId); | |||||
| useThingsOnResult(things); | |||||
| } | |||||
| catch(IllegalArgumentException ex) { | |||||
| MessageDialog.openError(main.getShell(), "", ex.getMessage()); | |||||
| } | |||||
| } | |||||
| } else if(source == SourceFilter.FAMILY) { | |||||
| Integer familyId = resultConfig.familyId; | |||||
| if(familyId == null) { | |||||
| MessageDialog.openError(main.getShell(), "", "Please enter a family id."); | |||||
| return; | |||||
| } else { | |||||
| eventBroker.send(EventConstants.TOPIC_STATUS, "Fetching for family id '" + familyId + "'"); | |||||
| try { | |||||
| ArrayList<Thing> things = bggApi.getThingsForFamily(familyId); | |||||
| useThingsOnResult(things); | |||||
| } | |||||
| catch(IllegalArgumentException ex) { | |||||
| MessageDialog.openError(main.getShell(), "", ex.getMessage()); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| private void useThingsOnResult(ArrayList<Thing> things) { | |||||
| switch(configManager.getResultConfig().action) { | |||||
| case REP: | |||||
| thingProvider.replaceThings(things); | |||||
| break; | |||||
| case ADD: | |||||
| thingProvider.addThings(things); | |||||
| break; | |||||
| case SUB: | |||||
| thingProvider.subtractThings(things); | |||||
| break; | |||||
| case AND: | |||||
| thingProvider.intersectThings(things); | |||||
| break; | |||||
| case ONLY_NEW: | |||||
| thingProvider.keepOnlyNew(things); | |||||
| break; | |||||
| } | |||||
| eventBroker.send(EventConstants.TOPIC_RESULT_CHANGED, ""); | |||||
| eventBroker.send(EventConstants.TOPIC_STATUS, "Fetched " + Integer.toString(things.size()) + " things."); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,35 @@ | |||||
| package xyz.veronie.bgg.ui.parts.internal; | |||||
| import org.eclipse.jface.viewers.OwnerDrawLabelProvider; | |||||
| import org.eclipse.swt.graphics.Image; | |||||
| import org.eclipse.swt.graphics.Rectangle; | |||||
| import org.eclipse.swt.widgets.Event; | |||||
| import org.eclipse.swt.widgets.TableItem; | |||||
| public abstract class CenterImageLabelProvider extends OwnerDrawLabelProvider { | |||||
| protected void measure(Event event, Object element) { | |||||
| } | |||||
| protected void paint(Event event, Object element) { | |||||
| Image img = getImage(element); | |||||
| if (img != null) { | |||||
| Rectangle bounds = ((TableItem) event.item).getBounds(event.index); | |||||
| Rectangle imgBounds = img.getBounds(); | |||||
| bounds.width /= 2; | |||||
| bounds.width -= imgBounds.width / 2; | |||||
| bounds.height /= 2; | |||||
| bounds.height -= imgBounds.height / 2; | |||||
| int x = bounds.width > 0 ? bounds.x + bounds.width : bounds.x; | |||||
| int y = bounds.height > 0 ? bounds.y + bounds.height : bounds.y; | |||||
| event.gc.drawImage(img, x, y); | |||||
| } | |||||
| } | |||||
| protected abstract Image getImage(Object element); | |||||
| }; | |||||