IDEMPIERE-1379:Info Windows should have their own icon/image

move manage imageCache to ManageImageCache
improve imageCache for
  + don't load local image to cache
  + handle exception when wrong link or disconnect network
  + when many MImage has same extenal url, just load one time
  + tab for "info window" has same icon when display in daskboad view
This commit is contained in:
hieplq 2015-08-09 02:31:13 +08:00
parent e99cff2f02
commit 517f0299e1
7 changed files with 357 additions and 49 deletions

View File

@ -17,7 +17,6 @@
package org.adempiere.webui.adwindow; package org.adempiere.webui.adwindow;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -35,9 +34,7 @@ import org.compiere.model.MToolBarButton;
import org.compiere.model.MToolBarButtonRestrict; import org.compiere.model.MToolBarButtonRestrict;
import org.compiere.model.MWindow; import org.compiere.model.MWindow;
import org.compiere.model.X_AD_ToolBarButton; import org.compiere.model.X_AD_ToolBarButton;
import org.compiere.util.CCache;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.zkoss.image.AImage;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
/** /**
@ -60,8 +57,6 @@ public class ADWindow extends AbstractUIPart
private Component windowPanelComponent; private Component windowPanelComponent;
private MImage image; private MImage image;
private static final CCache<Integer, AImage> imageCache = new CCache<Integer, AImage>(null, "WindowImageCache", 5, false);
private Map<Integer, List<String>> tabToolbarRestricMap = new HashMap<Integer, List<String>>(); private Map<Integer, List<String>> tabToolbarRestricMap = new HashMap<Integer, List<String>>();
private List<String> windowToolbarRestrictList = null; private List<String> windowToolbarRestrictList = null;
@ -129,23 +124,6 @@ public class ADWindow extends AbstractUIPart
return image; return image;
} }
public AImage getAImage() throws IOException {
MImage image = getMImage();
AImage aImage = null;
if (image != null) {
synchronized (imageCache) {
aImage = imageCache.get(image.getAD_Image_ID());
}
if (aImage == null) {
aImage = new AImage(image.getName(), image.getData());
synchronized (imageCache) {
imageCache.put(image.getAD_Image_ID(), aImage);
}
}
}
return aImage;
}
protected Component doCreatePart(Component parent) protected Component doCreatePart(Component parent)
{ {
windowPanelComponent = windowContent.createPart(parent); windowPanelComponent = windowContent.createPart(parent);

View File

@ -17,6 +17,13 @@
package org.adempiere.webui.component; package org.adempiere.webui.component;
import org.adempiere.webui.adwindow.ADWindow;
import org.adempiere.webui.util.ManageImageCache;
import org.compiere.model.MImage;
import org.compiere.model.MInfoWindow;
import org.zkoss.image.Image;
import org.zkoss.zul.impl.LabelImageElement;
/** /**
* *
* @author <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a> * @author <a href="mailto:agramdass@gmail.com">Ashley G Ramdass</a>
@ -38,6 +45,11 @@ public class Tab extends org.zkoss.zul.Tab
public Tab() public Tab()
{ {
}
public void setDecorateInfo (DecorateInfo decorateInfo){
if (decorateInfo != null)
decorateInfo.decorate(this);
} }
@Override @Override
@ -48,4 +60,50 @@ public class Tab extends org.zkoss.zul.Tab
} }
} }
/**
* class contain decorate info
* at the moment, has only image info
* at the moment, it's use to transfer decorate info from info window, standard window, report, process,... to tab
* @author hieplq
*
*/
public static class DecorateInfo {
private String imageKey;
private String imageIntenalUrl;
public void decorate (LabelImageElement comp){
if (imageIntenalUrl != null)
comp.setImage(imageIntenalUrl);
else if (imageKey != null){
Image ico = ManageImageCache.instance().getImage(imageKey);
if (ico != null)
comp.setImageContent(ico);
}
}
public DecorateInfo (MImage imageData){
imageIntenalUrl = ManageImageCache.getImageInternalUrl(imageData);
if (imageIntenalUrl == null)
imageKey = ManageImageCache.instance().loadImage(imageData);
}
public DecorateInfo (String imagePath){
imageIntenalUrl = ManageImageCache.getImageInternalUrl(imagePath);
if (imageIntenalUrl == null)
imageKey = imagePath;
}
/**
* Helper method for create decorate info from adWindow info
* @param adWindow
* @return
*/
public static DecorateInfo get (ADWindow adWindow){
return adWindow == null?null:new DecorateInfo(adWindow.getMImage());
}
public static DecorateInfo get (MInfoWindow mInfo){
return mInfo==null?null:new DecorateInfo(mInfo.getImageURL());
}
}
} }

View File

@ -243,7 +243,7 @@ public class DefaultDesktop extends TabbedDesktop implements MenuListener, Seria
windowContainer.createPart(windowArea); windowContainer.createPart(windowArea);
homeTab = new Tabpanel(); homeTab = new Tabpanel();
windowContainer.addWindow(homeTab, Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Home")), false); windowContainer.addWindow(homeTab, Util.cleanAmp(Msg.getMsg(Env.getCtx(), "Home")), false, null);
homeTab.getLinkedTab().setSclass("desktop-hometab"); homeTab.getLinkedTab().setSclass("desktop-hometab");
homeTab.setSclass("desktop-home-tabpanel"); homeTab.setSclass("desktop-home-tabpanel");
BusyDialog busyDialog = new BusyDialog(); BusyDialog busyDialog = new BusyDialog();

View File

@ -13,7 +13,6 @@
*****************************************************************************/ *****************************************************************************/
package org.adempiere.webui.desktop; package org.adempiere.webui.desktop;
import java.io.IOException;
import java.util.List; import java.util.List;
import org.adempiere.util.Callback; import org.adempiere.util.Callback;
@ -22,6 +21,7 @@ import org.adempiere.webui.adwindow.ADWindow;
import org.adempiere.webui.apps.ProcessDialog; import org.adempiere.webui.apps.ProcessDialog;
import org.adempiere.webui.apps.wf.WFPanel; import org.adempiere.webui.apps.wf.WFPanel;
import org.adempiere.webui.component.DesktopTabpanel; import org.adempiere.webui.component.DesktopTabpanel;
import org.adempiere.webui.component.Tab.DecorateInfo;
import org.adempiere.webui.component.Tabbox; import org.adempiere.webui.component.Tabbox;
import org.adempiere.webui.component.Tabpanel; import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.Window; import org.adempiere.webui.component.Window;
@ -32,11 +32,11 @@ import org.adempiere.webui.panel.InfoPanel;
import org.adempiere.webui.part.WindowContainer; import org.adempiere.webui.part.WindowContainer;
import org.adempiere.webui.window.FDialog; import org.adempiere.webui.window.FDialog;
import org.adempiere.webui.window.WTask; import org.adempiere.webui.window.WTask;
import org.compiere.model.MInfoWindow;
import org.compiere.model.MQuery; import org.compiere.model.MQuery;
import org.compiere.model.MTask; import org.compiere.model.MTask;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.wf.MWorkflow; import org.compiere.wf.MWorkflow;
import org.zkoss.image.AImage;
import org.zkoss.util.media.AMedia; import org.zkoss.util.media.AMedia;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
@ -73,7 +73,7 @@ public abstract class TabbedDesktop extends AbstractDesktop {
String title = pd.getTitle(); String title = pd.getTitle();
pd.setTitle(null); pd.setTitle(null);
preOpenNewTab(); preOpenNewTab();
windowContainer.addWindow(tabPanel, title, true); windowContainer.addWindow(tabPanel, title, true, null);
Events.postEvent(ProcessDialog.ON_INITIAL_FOCUS_EVENT, pd, null); Events.postEvent(ProcessDialog.ON_INITIAL_FOCUS_EVENT, pd, null);
} }
return pd; return pd;
@ -93,7 +93,7 @@ public abstract class TabbedDesktop extends AbstractDesktop {
//do not show window title when open as tab //do not show window title when open as tab
form.setTitle(null); form.setTitle(null);
preOpenNewTab(); preOpenNewTab();
windowContainer.addWindow(tabPanel, form.getFormName(), true); windowContainer.addWindow(tabPanel, form.getFormName(), true, null);
form.focus(); form.focus();
} else { } else {
form.setAttribute(Window.MODE_KEY, form.getWindowMode()); form.setAttribute(Window.MODE_KEY, form.getWindowMode());
@ -117,7 +117,7 @@ public abstract class TabbedDesktop extends AbstractDesktop {
String title = infoPanel.getTitle(); String title = infoPanel.getTitle();
infoPanel.setTitle(null); infoPanel.setTitle(null);
preOpenNewTab(); preOpenNewTab();
windowContainer.addWindow(tabPanel, title, true); windowContainer.addWindow(tabPanel, title, true, DecorateInfo.get(MInfoWindow.get(infoId, null)));
infoPanel.focus(); infoPanel.focus();
} else { } else {
FDialog.error(0, "NotValid"); FDialog.error(0, "NotValid");
@ -135,7 +135,7 @@ public abstract class TabbedDesktop extends AbstractDesktop {
DesktopTabpanel tabPanel = new DesktopTabpanel(); DesktopTabpanel tabPanel = new DesktopTabpanel();
p.setParent(tabPanel); p.setParent(tabPanel);
preOpenNewTab(); preOpenNewTab();
windowContainer.addWindow(tabPanel, p.getWorkflow().get_Translation(MWorkflow.COLUMNNAME_Name), true); windowContainer.addWindow(tabPanel, p.getWorkflow().get_Translation(MWorkflow.COLUMNNAME_Name), true, null);
} }
/** /**
@ -160,7 +160,8 @@ public abstract class TabbedDesktop extends AbstractDesktop {
final DesktopTabpanel tabPanel = new DesktopTabpanel(); final DesktopTabpanel tabPanel = new DesktopTabpanel();
String id = AdempiereIdGenerator.escapeId(adWindow.getTitle()); String id = AdempiereIdGenerator.escapeId(adWindow.getTitle());
tabPanel.setId(id+"_"+adWindow.getADWindowContent().getWindowNo()); tabPanel.setId(id+"_"+adWindow.getADWindowContent().getWindowNo());
final Tab tab = windowContainer.addWindow(tabPanel, adWindow.getTitle(), true); final Tab tab = windowContainer.addWindow(tabPanel, adWindow.getTitle(), true, DecorateInfo.get(adWindow));
tab.setClosable(false); tab.setClosable(false);
final OpenWindowRunnable runnable = new OpenWindowRunnable(adWindow, tab, tabPanel, callback); final OpenWindowRunnable runnable = new OpenWindowRunnable(adWindow, tab, tabPanel, callback);
preOpenNewTab(); preOpenNewTab();
@ -233,7 +234,7 @@ public abstract class TabbedDesktop extends AbstractDesktop {
Tabpanel tabPanel = new Tabpanel(); Tabpanel tabPanel = new Tabpanel();
window.setParent(tabPanel); window.setParent(tabPanel);
preOpenNewTab(); preOpenNewTab();
windowContainer.addWindow(tabPanel, title, closeable); windowContainer.addWindow(tabPanel, title, closeable, null);
} }
/** /**
@ -245,7 +246,7 @@ public abstract class TabbedDesktop extends AbstractDesktop {
final ADWindow wnd = new ADWindow(Env.getCtx(), AD_Window_ID, query); final ADWindow wnd = new ADWindow(Env.getCtx(), AD_Window_ID, query);
final DesktopTabpanel tabPanel = new DesktopTabpanel(); final DesktopTabpanel tabPanel = new DesktopTabpanel();
final Tab tab = windowContainer.insertAfter(windowContainer.getSelectedTab(), tabPanel, wnd.getTitle(), true, true); final Tab tab = windowContainer.insertAfter(windowContainer.getSelectedTab(), tabPanel, wnd.getTitle(), true, true, DecorateInfo.get(wnd));
tab.setClosable(false); tab.setClosable(false);
final OpenWindowRunnable runnable = new OpenWindowRunnable(wnd, tab, tabPanel, null); final OpenWindowRunnable runnable = new OpenWindowRunnable(wnd, tab, tabPanel, null);
preOpenNewTab(); preOpenNewTab();
@ -277,9 +278,9 @@ public abstract class TabbedDesktop extends AbstractDesktop {
window.setTitle(null); window.setTitle(null);
preOpenNewTab(); preOpenNewTab();
if (Window.INSERT_NEXT.equals(window.getAttribute(Window.INSERT_POSITION_KEY))) if (Window.INSERT_NEXT.equals(window.getAttribute(Window.INSERT_POSITION_KEY)))
windowContainer.insertAfter(windowContainer.getSelectedTab(), tabPanel, title, true, true); windowContainer.insertAfter(windowContainer.getSelectedTab(), tabPanel, title, true, true, null);
else else
windowContainer.addWindow(tabPanel, title, true); windowContainer.addWindow(tabPanel, title, true, null);
if (window instanceof IHelpContext) if (window instanceof IHelpContext)
Events.sendEvent(new Event(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, window)); Events.sendEvent(new Event(WindowContainer.ON_WINDOW_CONTAINER_SELECTION_CHANGED_EVENT, window));
} }
@ -381,13 +382,6 @@ public abstract class TabbedDesktop extends AbstractDesktop {
public void run() { public void run() {
if (adWindow.createPart(tabPanel) != null ) { if (adWindow.createPart(tabPanel) != null ) {
tab.setClosable(true); tab.setClosable(true);
if (adWindow.getMImage() != null) {
try {
AImage aImage = adWindow.getAImage();
tab.setImageContent(aImage);
} catch (IOException e) {
}
}
if (callback != null) { if (callback != null) {
callback.onCallback(adWindow); callback.onCallback(adWindow);
} }

View File

@ -17,6 +17,7 @@ import java.util.List;
import org.adempiere.webui.component.Menupopup; import org.adempiere.webui.component.Menupopup;
import org.adempiere.webui.component.Tab; import org.adempiere.webui.component.Tab;
import org.adempiere.webui.component.Tab.DecorateInfo;
import org.adempiere.webui.component.Tabbox; import org.adempiere.webui.component.Tabbox;
import org.adempiere.webui.component.Tabpanel; import org.adempiere.webui.component.Tabpanel;
import org.adempiere.webui.component.Tabpanels; import org.adempiere.webui.component.Tabpanels;
@ -101,15 +102,63 @@ public class WindowContainer extends AbstractUIPart
return tabbox; return tabbox;
} }
/**
* @deprecated keep for compatible, replace by {@link #addWindow(Component, String, boolean, DecorateInfo)}
* @param comp
* @param title
* @param closeable
* @return
*/
public Tab addWindow(Component comp, String title, boolean closeable){
return addWindow(comp, title, closeable, true, null);
}
/**
* @deprecated keep for compatible, replace by {@link #addWindow(Component, String, boolean, boolean, DecorateInfo)}
* @param comp
* @param title
* @param closeable
* @param enable
* @return
*/
public Tab addWindow(Component comp, String title, boolean closeable, boolean enable) {
return addWindow(comp, title, closeable, true, null);
}
/**
* @deprecated keep for compatible, replace by {@link #insertBefore(Tab, Component, String, boolean, boolean, DecorateInfo)}
* @param refTab
* @param comp
* @param title
* @param closeable
* @param enable
* @return
*/
public Tab insertBefore(Tab refTab, Component comp, String title, boolean closeable, boolean enable){
return insertBefore(refTab, comp, title, closeable, enable, null);
}
/**
* @deprecated keep for compatible, replace by {@link #insertAfter(Component, String, boolean, boolean, DecorateInfo)}
* @param refTab
* @param comp
* @param title
* @param closeable
* @param enable
* @return
*/
public Tab insertAfter(Tab refTab, Component comp, String title, boolean closeable, boolean enable){
return insertAfter(refTab, comp, title, closeable, enable, null);
}
/** /**
* *
* @param comp * @param comp
* @param title * @param title
* @param closeable * @param closeable
*/ */
public Tab addWindow(Component comp, String title, boolean closeable) public Tab addWindow(Component comp, String title, boolean closeable, DecorateInfo decorateInfo)
{ {
return addWindow(comp, title, closeable, true); return addWindow(comp, title, closeable, true, decorateInfo);
} }
/** /**
@ -119,9 +168,9 @@ public class WindowContainer extends AbstractUIPart
* @param closeable * @param closeable
* @param enable * @param enable
*/ */
public Tab addWindow(Component comp, String title, boolean closeable, boolean enable) public Tab addWindow(Component comp, String title, boolean closeable, boolean enable, DecorateInfo decorateInfo)
{ {
return insertBefore(null, comp, title, closeable, enable); return insertBefore(null, comp, title, closeable, enable, decorateInfo);
} }
/** /**
@ -132,9 +181,10 @@ public class WindowContainer extends AbstractUIPart
* @param closeable * @param closeable
* @param enable * @param enable
*/ */
public Tab insertBefore(Tab refTab, Component comp, String title, boolean closeable, boolean enable) public Tab insertBefore(Tab refTab, Component comp, String title, boolean closeable, boolean enable, DecorateInfo decorateInfo)
{ {
final Tab tab = new Tab(); final Tab tab = new Tab();
tab.setDecorateInfo(decorateInfo);
if (title != null) if (title != null)
{ {
setTabTitle(title, tab); setTabTitle(title, tab);
@ -318,12 +368,12 @@ public class WindowContainer extends AbstractUIPart
* @param closeable * @param closeable
* @param enable * @param enable
*/ */
public Tab insertAfter(Tab refTab, Component comp, String title, boolean closeable, boolean enable) public Tab insertAfter(Tab refTab, Component comp, String title, boolean closeable, boolean enable, DecorateInfo decorateInfo)
{ {
if (refTab == null) if (refTab == null)
return addWindow(comp, title, closeable, enable); return addWindow(comp, title, closeable, enable, decorateInfo);
else else
return insertBefore((Tab)refTab.getNextSibling(), comp, title, closeable, enable); return insertBefore((Tab)refTab.getNextSibling(), comp, title, closeable, enable, decorateInfo);
} }
/** /**

View File

@ -0,0 +1,223 @@
/**********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
**********************************************************************/
package org.adempiere.webui.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import org.adempiere.base.Core;
import org.compiere.model.MImage;
import org.compiere.util.CCache;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.zkoss.image.AImage;
import org.zkoss.image.Image;
/**
* Normal image can come from inside system or from outside system.
* with image from outside for performance we will cache it.
* this class for manage image cache and provide help function relate
* @author hieplq
*
*/
public class ManageImageCache {
protected static transient CLogger log = CLogger.getCLogger (ManageImageCache.class);
/**
* this cache is don't expire, if must restart cache when has update image.
* better use a timer, example reset cache after 10 minute has update. it help user can change a batch of image and reset one time.
*/
private final CCache<String, Image> imageCache = new CCache<String, Image>(null, "WindowImageCache", 50, 0, false);
private static ManageImageCache instance;
/**
* get instance
* @return
*/
public static ManageImageCache instance(){
if (instance == null){
synchronized (ManageImageCache.class){
if (instance == null)
instance = new ManageImageCache();
}
}
return instance;
}
/**
* investigate image path of MImage, if path is a internal return internal url other return null
* @param image
* @return
*/
public static String getImageInternalUrl (MImage image){
if (image == null)
return null;
return getImageInternalUrl(image.getImageURL());
}
/**
* investigate image path, if path is a internal return internal url other return null
* @param url
* @return
*/
public static String getImageInternalUrl (String url){
if (url == null || url.trim().length() == 0 || url.indexOf("://") > 0)
return null;
URL urlRsource = Core.getResourceFinder().getResource(url);
return urlRsource == null?null:urlRsource.getPath();
}
/**
* Load image from url
* @param imagePath
* @return
*/
protected static byte [] loadImageData (String imagePath){
byte [] data = null;
URLConnection conn;
try {
URL url = new URL(imagePath);
conn = url.openConnection();
conn.setUseCaches(false);
InputStream is = conn.getInputStream();
byte[] buffer = new byte[1024*8]; // 8kB
ByteArrayOutputStream os = new ByteArrayOutputStream();
int length = -1;
while ((length = is.read(buffer)) != -1)
os.write(buffer, 0, length);
is.close();
data = os.toByteArray();
os.close();
} catch (IOException e) {
if (log.isLoggable(Level.CONFIG)) log.config (e.toString());
}
return data;
}
/**
* if image is don't in cache, load it (imagePath can id of MImage)
* @param imagePath
* @return image load from path. null when has any exception
*/
public Image getImage(String imagePath){
if (imagePath == null || imagePath.trim().length() == 0)
return null;
Image aImage = null;
boolean hasCache = false;
synchronized (imageCache) {
hasCache = imageCache.containsKey(imagePath);
}
if (!hasCache) {
try{
int mImageId = Integer.parseInt(imagePath);
loadImage(MImage.get(Env.getCtx(), mImageId));
}catch (NumberFormatException ex){
loadExtend(imagePath);
}
}
synchronized (imageCache) {
aImage = imageCache.get(imagePath);
}
return aImage;
}
/**
* if MImage contain extend image or binary image data, load it into cache and return key
* other return null
* @param mImage
* @return
*/
public String loadImage (MImage mImage){
if (mImage == null)
return null;
boolean hasCache = false;
String strId = String.valueOf(mImage.get_ID());
synchronized (imageCache) {
hasCache = imageCache.containsKey(strId);
}
if(hasCache){
return strId;
}
if (mImage.getBinaryData() != null){
synchronized (imageCache) {
Image loadImage = null;
try {
loadImage = new AImage (mImage.getName(), mImage.getBinaryData());
} catch (IOException e) {
// do nothing treat image as null
}
imageCache.put(String.valueOf(mImage.get_ID()), loadImage);
}
return strId;
}else if (mImage.getImageURL() != null && mImage.getImageURL().trim().length() > 0 && getImageInternalUrl(mImage.getImageURL()) == null){
synchronized (imageCache) {
hasCache = imageCache.containsKey(mImage.getImageURL());
}
if (!hasCache){
loadExtend (mImage.getImageURL());
}
return mImage.getImageURL();
}
return null;
}
/**
* load extend image into cache
* @param imagePath
*/
protected void loadExtend (String imagePath){
byte[] data = loadImageData(imagePath);
AImage aImage = null;
// when can't load image (by incorrect url or disconnect or any exception, just set image as null
if (data != null)
try {
aImage = new AImage(imagePath, data);
} catch (IOException e) {
aImage = null;
}
synchronized (imageCache) {
imageCache.put(imagePath, aImage);
}
}
}

View File

@ -15,6 +15,7 @@ package org.adempiere.webui.util;
import java.net.URL; import java.net.URL;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.regex.Pattern;
import org.adempiere.base.IResourceFinder; import org.adempiere.base.IResourceFinder;
import org.adempiere.webui.WebUIActivator; import org.adempiere.webui.WebUIActivator;
@ -40,6 +41,7 @@ public class WebUIResourceFinder implements IResourceFinder {
return WebUIActivator.getBundleContext().getBundle().findEntries(path, pattern, false); return WebUIActivator.getBundleContext().getBundle().findEntries(path, pattern, false);
} }
protected Pattern patternOnlyName = Pattern.compile("\\w+\\.\\w+");
@Override @Override
public URL getResource(String name) { public URL getResource(String name) {
if ("images/iDempiereHR.png".equals(name) || "images/iDempiere.png".equals(name)) { if ("images/iDempiereHR.png".equals(name) || "images/iDempiere.png".equals(name)) {
@ -47,6 +49,9 @@ public class WebUIResourceFinder implements IResourceFinder {
} }
Enumeration<URL> e = find(name); Enumeration<URL> e = find(name);
URL url = e != null && e.hasMoreElements() ? e.nextElement() : null; URL url = e != null && e.hasMoreElements() ? e.nextElement() : null;
if (url == null && patternOnlyName.matcher(name).matches()){
name = "images/" + name;
}
if (url == null && name.startsWith("org/compiere/images")) { if (url == null && name.startsWith("org/compiere/images")) {
String t = name.substring("org/compiere/".length()); String t = name.substring("org/compiere/".length());
t = ThemeManager.getThemeResource(t); t = ThemeManager.getThemeResource(t);