Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "Scout/HowTo/4.0/Uncached images and icons"
(Created page with "{{ScoutPage|cat=HowTo 4.0}} This how-to describes how to work with uncached images and icons. = Background = When using icons/images in a table or a form an <code>IconLo...") |
m |
||
Line 34: | Line 34: | ||
| valign="top" | '''Detailed steps needed:''' | | valign="top" | '''Detailed steps needed:''' | ||
| | | | ||
− | *Create the class org. | + | *Create the class org.eclipsescout.demoscout.demo.minicrm.ui.swing.'''SwingUncachedIconLocator''': |
<pre>public class SwingUncachedIconLocator extends SwingIconLocator { | <pre>public class SwingUncachedIconLocator extends SwingIconLocator { | ||
private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwingUncachedIconLocator.class); | private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwingUncachedIconLocator.class); | ||
Line 86: | Line 86: | ||
} | } | ||
</pre> | </pre> | ||
− | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.IImageField''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.IImageField''' and save it as '''org.eclipsescout.demo.minicrm.client.form.fields.ext.IUncachedImageField''' and replace all occurences of "ImageField" with "UncachedImageField" |
− | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.IImageFieldUIFacade''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.IImageFieldUIFacade''' and save it as '''org.eclipsescout.demo.minicrm.client.form.fields.ext.IUncachedImageFieldUIFacade''' and replace all occurences of "ImageField" with "UncachedImageField" |
− | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.ImageFieldEvent''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.ImageFieldEvent''' and save it as '''org.eclipsescout.demo.minicrm.client.form.fields.ext.UncachedImageFieldEvent''' and replace all occurences of "ImageField" with "UncachedImageField" |
− | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.ImageFieldListener''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.ImageFieldListener''' and save it as '''org.eclipsescout.demo.minicrm.client.form.fields.ext.UncachedImageFieldListener''' and replace all occurences of "ImageField" with "UncachedImageField" |
− | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.AbstractImageField''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.client.ui.form.fields.imagebox.AbstractImageField''' and save it as '''org.eclipsescout.demo.minicrm.client.form.fields.ext.AbstractUncachedImageField''' and replace all occurences of "ImageField" with "UncachedImageField" |
− | *Open '''org.eclipse.scout.rt.ui.swing.form.fields.imagebox.ISwingScoutImageField''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.ui.swing.form.fields.imagebox.ISwingScoutImageField''' and save it as '''org.eclipsescout.demo.minicrm.ui.swing.form.fields.ext.ISwingScoutUncachedImageField''' and replace all occurences of "ImageField" with "UncachedImageField" |
− | *Open '''org.eclipse.scout.rt.ui.swing.form.fields.imagebox.SwingScoutImageField''' and save it as '''org. | + | *Open '''org.eclipse.scout.rt.ui.swing.form.fields.imagebox.SwingScoutImageField''' and save it as '''org.eclipsescout.demo.minicrm.ui.swing.form.fields.ext.SwingScoutUncachedImageField''' and replace all occurences of "ImageField" with "UncachedImageField",<br>then add the following code: |
<pre> private SwingUncachedIconLocator m_uncachedIconLocator; | <pre> private SwingUncachedIconLocator m_uncachedIconLocator; | ||
Line 151: | Line 151: | ||
| | | | ||
− | *Create the class org. | + | *Create the class org.eclipsescout.demo.minicrm.ui.swing.'''SwingUncachedIconLocator '''as described above. |
− | *Create a plugin project org. | + | *Create a plugin project org.eclipsescout.demo.minicrm.scout.rt.ui.swing |
− | *Make sure the package '''org. | + | *Make sure the package '''org.eclipsescout.demo.minicrm.scout.rt.ui.swing.form.fields''' is exported in MANIFEST.MF |
− | *Create a class '''org. | + | *Create a class '''org.eclipsescout.demo.minicrm.scout.rt.ui.swing.form.fields.SwingScoutUncachedImageField''' with the following content: |
<pre>public class SwingScoutUncachedImageField extends SwingScoutImageField { | <pre>public class SwingScoutUncachedImageField extends SwingScoutImageField { | ||
private SwingUncachedIconLocator m_uncachedIconLocator; | private SwingUncachedIconLocator m_uncachedIconLocator; | ||
Line 190: | Line 190: | ||
name="imagefield"> | name="imagefield"> | ||
<uiClass | <uiClass | ||
− | class="org. | + | class="org.eclipsescout.demo.minicrm.scout.rt.ui.swing.form.fields.SwingScoutUncachedImageField"> |
</uiClass> | </uiClass> | ||
</formField> | </formField> | ||
Line 225: | Line 225: | ||
| valign="top" | '''Detailed steps needed:''' | | valign="top" | '''Detailed steps needed:''' | ||
| | | | ||
− | *Create the class org. | + | *Create the class org.eclipsescout.demo.minicrm.ui.swing.'''SwingUncachedIconLocator''' as described above. |
− | *Add the following method to org. | + | *Add the following method to org.eclipsescout.demo.minicrm.ui.swing.'''SwingEnvironment''': |
<pre> protected SwingIconLocator createIconLocator() { | <pre> protected SwingIconLocator createIconLocator() { | ||
return new SwingUncachedIconLocator(getScoutSession().getIconLocator()); | return new SwingUncachedIconLocator(getScoutSession().getIconLocator()); | ||
Line 262: | Line 262: | ||
| valign="top" | '''Detailed steps needed:''' | | valign="top" | '''Detailed steps needed:''' | ||
| | | | ||
− | *Create the class org. | + | *Create the class org.eclipsescout.demo.minicrm.ui.swing.'''SwingUncachedIconLocator''' as described above. |
− | *Create a class org. | + | *Create a class org.eclipsescout.demo.minicrm.ui.swing.'''SwingScoutUncachedImageField''' with the following content: |
<pre>public class SwingScoutUncachedImageField extends SwingScoutImageField { | <pre>public class SwingScoutUncachedImageField extends SwingScoutImageField { | ||
private SwingUncachedIconLocator m_uncachedIconLocator; | private SwingUncachedIconLocator m_uncachedIconLocator; | ||
Line 290: | Line 290: | ||
} | } | ||
</pre> | </pre> | ||
− | *Add the following method to org. | + | *Add the following method to org.eclipsescout.demo.minicrm.ui.swing.'''SwingEnvironment''': |
<pre>@Override | <pre>@Override | ||
public ISwingScoutFormField<?> createFormField(JComponent parent, IFormField field) { | public ISwingScoutFormField<?> createFormField(JComponent parent, IFormField field) { | ||
Line 396: | Line 396: | ||
<pre> String imageId = "Image-" + keyValue + staticCounter++; | <pre> String imageId = "Image-" + keyValue + staticCounter++; | ||
content = SERVICES.getService(IMyProcessService.class).loadImage(imageId); | content = SERVICES.getService(IMyProcessService.class).loadImage(imageId); | ||
− | org. | + | org.eclipsescout.demo.minicrm.client.Activator.getDefault().cacheImage(imageId, content); |
getUncachedImageField().setImageId(imageId); | getUncachedImageField().setImageId(imageId); | ||
</pre> | </pre> | ||
Line 440: | Line 440: | ||
String imageId = md5; | String imageId = md5; | ||
content = SERVICES.getService(IMyProcessService.class).loadImage(imageId); | content = SERVICES.getService(IMyProcessService.class).loadImage(imageId); | ||
− | org. | + | org.eclipsescout.demo.minicrm.client.Activator.getDefault().cacheImage(imageId, content); |
getUncachedImageField().setImageId(imageId); | getUncachedImageField().setImageId(imageId); | ||
} else { | } else { | ||
Line 451: | Line 451: | ||
String keyValue = getKeyValueColumn().getValue(row); | String keyValue = getKeyValueColumn().getValue(row); | ||
String imageId = getValue(row); // this is the MD5 checksum | String imageId = getValue(row); // this is the MD5 checksum | ||
− | if (!org. | + | if (!org.eclipsescout.demo.minicrm.client.Activator.getDefault().isImageCached(imageId)) { |
byte[] content = SERVICES.getService(IMyProcessService.class).loadImage(keyValue); | byte[] content = SERVICES.getService(IMyProcessService.class).loadImage(keyValue); | ||
− | org. | + | org.eclipsescout.demo.minicrm.client.Activator.getDefault().cacheImage(imageId, content); |
} | } | ||
cell.setIconId(imageId); | cell.setIconId(imageId); |
Revision as of 07:38, 15 May 2014
The Scout documentation has been moved to https://eclipsescout.github.io/.
This how-to describes how to work with uncached images and icons.
Contents
- 1 Background
- 2 Solutions
- 2.1 Custom field: UncachedImageField
- 2.2 Extending SwingScoutImageField
- 2.3 Overwrite SwingEnvironment.createIconLocator
- 2.4 Extending SwingScoutImageField and overwriting SwingEnvironment.createFormField
- 2.5 Use ImageField.setImage() instead of ImageField.setImageId()
- 2.6 Not re-using iconId
- 2.7 Use MD5 checksum as iconId
- 3 Recommended solution
Background
When using icons/images in a table or a form an IconLocator
(which in turn uses a [IconProviderService
]) is used. The default IconLocator
used for the Swing environment is org.eclipse.scout.rt.ui.swing.SwingIconLocator
, the one for the SWT environment is SWTIconLocator
. The SwingIconLocator caches the images when they are first requested. This means that whenever a setIconId()
method on a form field or table column is called with an iconId
that has previously been used, the first image retrieved under that name will be returned, even if the image has changed since then (because it has changed on disk, for example).
There are various options to work around this but while all of them will work for form fields (AbstractImageField
), not all of them work for table columns. This page tries to list the various methods that can be used together with their advantages and disadvantages.
Solutions
Custom field: UncachedImageField
Synopsis: | Create a "deep" copy of the ImageField model and renderer and modify it to use an uncached IconLocator |
Advantages: |
|
Disadvantages: |
|
Status: | Not recommended |
Detailed steps needed: |
public class SwingUncachedIconLocator extends SwingIconLocator { private static final IScoutLogger LOG = ScoutLogManager.getLogger(SwingUncachedIconLocator.class); public static final Pattern IMAGE_WITH_STATE_PATTERN = Pattern.compile("(.*)(_active|_disabled|_mouse|_mouse_over|_open|_over|_pressed|_rollover|_selected)", Pattern.CASE_INSENSITIVE); private final Object m_cacheLock = new Object(); private IIconLocator m_iconLocator; public SwingUncachedIconLocator(IIconLocator iconLocator) { super(iconLocator); m_iconLocator = iconLocator; } @Override public Image getImage(String name) { if (name == null || AbstractIcons.Null.equals(name) || name.length() == 0) { return null; } Image img; synchronized (m_cacheLock) { img = createImageImpl(name); if (img == null) { img = autoCreateMissingImage(name); } if (LOG.isDebugEnabled()) { LOG.debug("load image '" + name + "' as " + img); } if (img == null) { warnImageNotFound(name); } } return img; } private Image createImageImpl(String name) { IconSpec iconSpec = m_iconLocator.getIconSpec(name); if (iconSpec != null) { Image img = Toolkit.getDefaultToolkit().createImage(iconSpec.getContent()); if (img != null) { //decorate window icon in development mode if (Platform.inDevelopmentMode() && name != null && name.matches("^(window\\d+|tray)$")) { img = decorateForDevelopment(img); } } return img; } return null; } }
private SwingUncachedIconLocator m_uncachedIconLocator; protected SwingUncachedIconLocator getUncachedIconLocator() { if (m_uncachedIconLocator == null) { m_uncachedIconLocator = new SwingUncachedIconLocator(getSwingEnvironment().getScoutSession().getIconLocator()); } return m_uncachedIconLocator; } and modify the setImageFromScout() method as follows: protected void setImageFromScout(String imageId, Object image) { if (image == null) { if (imageId != null) { // try to use uncached image image = getUncachedIconLocator().getImage(imageId); if (image == null) { // as fallback, use cached image image = getSwingEnvironment().getImage(imageId); } } } getSwingImageViewer().setImage(image); } |
.
Extending SwingScoutImageField
Synopsis: | Provide a new plugin in which UncachedSwingScoutImageField extends SwingScoutImageField and uses the UncachedIconLocator. |
Advantages: |
|
Disadvantages: |
|
Status: | Not recommended |
Detailed steps needed: Note: This solution has not been tried (though it should work) |
public class SwingScoutUncachedImageField extends SwingScoutImageField { private SwingUncachedIconLocator m_uncachedIconLocator; protected SwingUncachedIconLocator getUncachedIconLocator() { if (m_uncachedIconLocator == null) { m_uncachedIconLocator = new SwingUncachedIconLocator(getSwingEnvironment().getScoutSession().getIconLocator()); } return m_uncachedIconLocator; } @Override protected void setImageFromScout(String imageId, Object image) { if (image == null) { if (imageId != null) { // try to use uncached image image = getUncachedIconLocator().getImage(imageId); if (image == null) { // as fallback, use cached image image = getSwingEnvironment().getImage(imageId); } } } getSwingImageViewer().setImage(image); } }
<plugin> <extension point="org.eclipse.scout.rt.ui.swing.formfields"> <formField scope="global" active="true" modelClass="org.eclipse.scout.rt.client.ui.form.fields.imagebox.IImageField" name="imagefield"> <uiClass class="org.eclipsescout.demo.minicrm.scout.rt.ui.swing.form.fields.SwingScoutUncachedImageField"> </uiClass> </formField> </extension> </plugin> |
.
Overwrite SwingEnvironment.createIconLocator
Synopsis: | Overwriting SwingEnvironemtn.createIconLocator to always return a non-caching IconLocator |
Advantages: |
|
Disadvantages: |
|
Status: | Not recommended |
Detailed steps needed: |
protected SwingIconLocator createIconLocator() { return new SwingUncachedIconLocator(getScoutSession().getIconLocator()); } |
.
Extending SwingScoutImageField and overwriting SwingEnvironment.createFormField
Synopsis: | Extend |
Advantages: |
|
Disadvantages: |
|
Status: | Not recommended |
Detailed steps needed: |
public class SwingScoutUncachedImageField extends SwingScoutImageField { private SwingUncachedIconLocator m_uncachedIconLocator; protected SwingUncachedIconLocator getUncachedIconLocator() { if (m_uncachedIconLocator == null) { m_uncachedIconLocator = new SwingUncachedIconLocator(getSwingEnvironment().getScoutSession().getIconLocator()); } return m_uncachedIconLocator; } @Override protected void setImageFromScout(String imageId, Object image) { if (image == null) { if (imageId != null) { // try to use uncached image image = getUncachedIconLocator().getImage(imageId); if (image == null) { // as fallback, use cached image image = getSwingEnvironment().getImage(imageId); } } } getSwingImageViewer().setImage(image); } }
@Override public ISwingScoutFormField<?> createFormField(JComponent parent, IFormField field) { if (field instanceof IImageField /* && add further conditions here */) { SwingScoutUncachedImageField ui = new SwingScoutUncachedImageField(); ui.createField((IImageField) field, this); decorate(field, ui); return ui; } return super.createFormField(parent, field); } |
.
Use ImageField.setImage() instead of ImageField.setImageId()
Synopsis: | Instead of passing the loaded image to an IconProviderService and then calling setImageId(imageId) on the ImageField, the content is directly passed to the ImageField using setImage(content) |
Advantages: |
|
Disadvantages: |
|
Status: | Recommended |
Detailed steps needed: |
public class MyForm extends AbstractForm { private byte[] content;
content = SERVICES.getService(IMyProcessService.class).loadImage(keyValue); getImageField().setImage(content);
public void updateImageFile(File file) throws ProcessingException { if (file != null) { content = new byte[(int) file.length()]; DataInputStream dis; try { dis = new DataInputStream(new FileInputStream(file)); dis.readFully(content); dis.close(); getImageField().setImage(content); } catch (FileNotFoundException e) { throw new ProcessingException(e.getMessage()); } catch (IOException e) { throw new ProcessingException(e.getMessage()); } } }
content = null; getImageField().setImage(content); |
.
Not re-using iconId
Synopsis: | Instead of using the key of the record showing on the form as imageId, the imageId is increased every time the image content changes (or even whenever the image is set). |
Advantages: |
|
Disadvantages: |
|
Status: | Not recommended |
Detailed steps needed: |
String imageId = "Image-" + keyValue + staticCounter++; content = SERVICES.getService(IMyProcessService.class).loadImage(imageId); org.eclipsescout.demo.minicrm.client.Activator.getDefault().cacheImage(imageId, content); getUncachedImageField().setImageId(imageId); |
.
Use MD5 checksum as iconId
Synopsis: | Instead of using a constantly increasing imageId, independently of whether the image changed or not the MD5 checksum over the image data is used. This checksum only changes if the image content changed as well. The probability for identical MD5 checksums for different images is negligable. |
Advantages: |
|
Disadvantages: |
|
Status: | Recommended |
Detailed steps needed: |
if (content != null) { String md5; try { md5 = Base64Utility.encode(EncryptionUtility.signMD5(content)); } catch (NoSuchAlgorithmException e) { throw new ProcessingException("Could not create MD5 hash for person portrait: " + e.getMessage()); } String imageId = md5; content = SERVICES.getService(IMyProcessService.class).loadImage(imageId); org.eclipsescout.demo.minicrm.client.Activator.getDefault().cacheImage(imageId, content); getUncachedImageField().setImageId(imageId); } else { getUncachedImageField().setImageId(null); }
@Override protected void execDecorateCell(Cell cell, ITableRow row) throws ProcessingException { String keyValue = getKeyValueColumn().getValue(row); String imageId = getValue(row); // this is the MD5 checksum if (!org.eclipsescout.demo.minicrm.client.Activator.getDefault().isImageCached(imageId)) { byte[] content = SERVICES.getService(IMyProcessService.class).loadImage(keyValue); org.eclipsescout.demo.minicrm.client.Activator.getDefault().cacheImage(imageId, content); } cell.setIconId(imageId); cell.setText(null); } |
.
Recommended solution
Synopsis: | The recommended solution is to combine two of the methods above: |
Advantages: |
|
Disadvantages: |
|
.
.
.
.
.
.