1 package org
.argeo
.cms
.ui
.util
;
3 import static java
.nio
.charset
.StandardCharsets
.UTF_8
;
5 import java
.io
.BufferedReader
;
6 import java
.io
.IOException
;
7 import java
.io
.InputStream
;
8 import java
.io
.InputStreamReader
;
10 import java
.util
.ArrayList
;
11 import java
.util
.Enumeration
;
12 import java
.util
.List
;
15 import java
.util
.TreeSet
;
16 import java
.util
.stream
.Collectors
;
18 import org
.argeo
.cms
.ui
.CmsTheme
;
19 import org
.eclipse
.swt
.graphics
.Image
;
20 import org
.osgi
.framework
.Bundle
;
21 import org
.osgi
.framework
.BundleContext
;
24 * Simplifies the theming of an app (only RAP is supported at this stage).<br>
26 * Additional fonts listed in <code>/fonts.txt</code>.<br>
27 * Additional (standard CSS) header in <code>/header.css</code>.<br>
28 * RAP specific CSS files in <code>/rap/*.css</code>.<br>
29 * All images added as additional resources based on extensions
30 * <code>/ ** /*.{png,gif,jpeg,...}</code>.<br>
32 public class BundleCmsTheme
extends AbstractCmsTheme
{
33 public final static String DEFAULT_CMS_THEME_BUNDLE
= "org.argeo.theme.argeo2";
35 public final static String CMS_THEME_PROPERTY
= "argeo.cms.theme";
36 public final static String CMS_THEME_BUNDLE_PROPERTY
= "argeo.cms.theme.bundle";
38 // private final static Log log = LogFactory.getLog(BundleCmsTheme.class);
40 private String themeId
;
41 private Set
<String
> rapCssPaths
= new TreeSet
<>();
42 private Set
<String
> imagesPaths
= new TreeSet
<>();
44 private String headerCss
;
45 private List
<String
> fonts
= new ArrayList
<>();
47 private String basePath
;
48 private String rapCssPath
;
49 private Bundle themeBundle
;
51 public BundleCmsTheme() {
55 public void init(BundleContext bundleContext
, Map
<String
, String
> properties
) {
56 initResources(bundleContext
, null);
59 public void destroy(BundleContext bundleContext
, Map
<String
, String
> properties
) {
64 public BundleCmsTheme(BundleContext bundleContext
) {
65 this(bundleContext
, null);
69 public BundleCmsTheme(BundleContext bundleContext
, String symbolicName
) {
70 initResources(bundleContext
, symbolicName
);
73 private void initResources(BundleContext bundleContext
, String symbolicName
) {
74 if (symbolicName
== null) {
75 themeBundle
= bundleContext
.getBundle();
76 // basePath = "/theme/";
77 // cssPath = basePath;
79 themeBundle
= findThemeBundle(bundleContext
, symbolicName
);
83 // this.themeId = RWT.DEFAULT_THEME_ID;
84 this.themeId
= themeBundle
.getSymbolicName();
85 addRapStyleSheets(themeBundle
);
86 addResources("*.png");
87 addResources("*.gif");
88 addResources("*.jpg");
89 addResources("*.jpeg");
90 addResources("*.svg");
91 addResources("*.ico");
94 URL fontsUrl
= themeBundle
.getEntry(basePath
+ "fonts.txt");
95 if (fontsUrl
!= null) {
96 loadFontsUrl(fontsUrl
);
99 // common CSS header (plain CSS)
100 URL headerCssUrl
= themeBundle
.getEntry(basePath
+ "header.css");
101 if (headerCssUrl
!= null) {
102 try (BufferedReader buffer
= new BufferedReader(new InputStreamReader(headerCssUrl
.openStream(), UTF_8
))) {
103 headerCss
= buffer
.lines().collect(Collectors
.joining("\n"));
104 } catch (IOException e
) {
105 throw new IllegalArgumentException("Cannot read " + headerCssUrl
, e
);
110 public String
getHtmlHeaders() {
111 StringBuilder sb
= new StringBuilder();
112 if (headerCss
!= null) {
113 sb
.append("<style type='text/css'>\n");
114 sb
.append(headerCss
);
115 sb
.append("\n</style>\n");
117 for (String link
: fonts
) {
118 sb
.append("<link rel='stylesheet' href='");
122 if (sb
.length() == 0)
125 return sb
.toString();
128 void addRapStyleSheets(Bundle themeBundle
) {
129 Enumeration
<URL
> themeResources
= themeBundle
.findEntries(rapCssPath
, "*.css", true);
130 if (themeResources
== null)
132 while (themeResources
.hasMoreElements()) {
133 String resource
= themeResources
.nextElement().getPath();
134 // remove first '/' so that RWT registers it
135 resource
= resource
.substring(1);
136 if (!resource
.endsWith("/")) {
137 // if (rapCss.containsKey(resource))
138 // log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
139 // rapCss.put(resource, ssRL);
140 rapCssPaths
.add(resource
);
147 void loadFontsUrl(URL url
) {
148 try (BufferedReader in
= new BufferedReader(new InputStreamReader(url
.openStream(), UTF_8
))) {
150 while ((line
= in
.readLine()) != null) {
152 if (!line
.equals("") && !line
.startsWith("#")) {
156 } catch (IOException e
) {
157 throw new IllegalArgumentException("Cannot load URL " + url
, e
);
161 void addResources(String pattern
) {
162 Enumeration
<URL
> themeResources
= themeBundle
.findEntries(basePath
, pattern
, true);
163 if (themeResources
== null)
165 while (themeResources
.hasMoreElements()) {
166 String resource
= themeResources
.nextElement().getPath();
167 // remove first '/' so that RWT registers it
168 resource
= resource
.substring(1);
169 if (!resource
.endsWith("/")) {
170 // if (resources.containsKey(resource))
171 // log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
172 // resources.put(resource, themeBRL);
173 imagesPaths
.add(resource
);
181 public InputStream
getResourceAsStream(String resourceName
) throws IOException
{
182 URL res
= themeBundle
.getEntry(resourceName
);
184 res
= themeBundle
.getResource(resourceName
);
187 // throw new IllegalArgumentException(
188 // "Resource " + resourceName + " not found in bundle " + themeBundle.getSymbolicName());
190 return res
.openStream();
193 public String
getThemeId() {
198 // public void setThemeId(String themeId) {
199 // this.themeId = themeId;
202 // public String getBasePath() {
206 // public void setBasePath(String basePath) {
207 // this.basePath = basePath;
210 // public String getRapCssPath() {
211 // return rapCssPath;
214 // public void setRapCssPath(String cssPath) {
215 // this.rapCssPath = cssPath;
219 public Set
<String
> getRapCssPaths() {
224 public Set
<String
> getImagesPaths() {
228 private static Bundle
findThemeBundle(BundleContext bundleContext
, String themeId
) {
232 // TODO deal with multiple versions
233 Bundle themeBundle
= null;
234 if (themeId
!= null) {
235 for (Bundle bundle
: bundleContext
.getBundles())
236 if (themeId
.equals(bundle
.getSymbolicName())) {
237 themeBundle
= bundle
;