1 package org
.argeo
.cms
.util
;
3 import static java
.nio
.charset
.StandardCharsets
.UTF_8
;
5 import java
.io
.BufferedReader
;
6 import java
.io
.IOException
;
7 import java
.io
.InputStreamReader
;
9 import java
.util
.ArrayList
;
10 import java
.util
.Enumeration
;
11 import java
.util
.HashMap
;
12 import java
.util
.List
;
14 import java
.util
.stream
.Collectors
;
16 import org
.apache
.commons
.logging
.Log
;
17 import org
.apache
.commons
.logging
.LogFactory
;
18 import org
.argeo
.cms
.CmsException
;
19 import org
.eclipse
.rap
.rwt
.RWT
;
20 import org
.eclipse
.rap
.rwt
.application
.Application
;
21 import org
.eclipse
.rap
.rwt
.service
.ResourceLoader
;
22 import org
.osgi
.framework
.Bundle
;
23 import org
.osgi
.framework
.BundleContext
;
26 * Simplifies the theming of an app (only RAP is supported at this stage).<br>
28 * Additional fonts listed in <code>/fonts.txt</code>.<br>
29 * Additional (standard CSS) header in <code>/header.css</code>.<br>
30 * RAP specific CSS files in <code>/rap/*.css</code>.<br>
31 * All images added as additional resources based on extensions
32 * <code>/ ** /*.{png,gif,jpeg,...}</code>.<br>
34 public class CmsTheme
{
35 private final static Log log
= LogFactory
.getLog(CmsTheme
.class);
37 private String themeId
;
38 private Map
<String
, ResourceLoader
> css
= new HashMap
<>();
39 private Map
<String
, ResourceLoader
> resources
= new HashMap
<>();
41 private String headerCss
;
42 private List
<String
> fonts
= new ArrayList
<>();
44 private String basePath
;
45 private String cssPath
;
47 public CmsTheme(BundleContext bundleContext
) {
48 this(bundleContext
, null);
51 public CmsTheme(BundleContext bundleContext
, String symbolicName
) {
53 if (symbolicName
== null) {
54 themeBundle
= bundleContext
.getBundle();
55 // basePath = "/theme/";
56 // cssPath = basePath;
58 themeBundle
= ThemeUtils
.findThemeBundle(bundleContext
, symbolicName
);
62 this.themeId
= RWT
.DEFAULT_THEME_ID
;
63 addStyleSheets(themeBundle
, new BundleResourceLoader(themeBundle
));
64 BundleResourceLoader themeBRL
= new BundleResourceLoader(themeBundle
);
65 addResources(themeBRL
, "*.png");
66 addResources(themeBRL
, "*.gif");
67 addResources(themeBRL
, "*.jpg");
68 addResources(themeBRL
, "*.jpeg");
69 addResources(themeBRL
, "*.svg");
70 addResources(themeBRL
, "*.ico");
73 URL fontsUrl
= themeBundle
.getEntry(basePath
+ "fonts.txt");
74 if (fontsUrl
!= null) {
75 loadFontsUrl(fontsUrl
);
78 // common CSS header (plain CSS)
79 URL headerCssUrl
= themeBundle
.getEntry(basePath
+ "header.css");
80 if (headerCssUrl
!= null) {
81 try (BufferedReader buffer
= new BufferedReader(new InputStreamReader(headerCssUrl
.openStream(), UTF_8
))) {
82 headerCss
= buffer
.lines().collect(Collectors
.joining("\n"));
83 } catch (IOException e
) {
84 throw new CmsException("Cannot read " + headerCssUrl
, e
);
90 public void apply(Application application
) {
91 resources
: for (String name
: resources
.keySet()) {
92 if (name
.startsWith("target/"))
93 continue resources
; // skip maven output
94 application
.addResource(name
, resources
.get(name
));
95 if (log
.isDebugEnabled())
96 log
.debug("Added resource " + name
);
98 for (String name
: css
.keySet()) {
99 application
.addStyleSheet(themeId
, name
, css
.get(name
));
100 if (log
.isDebugEnabled())
101 log
.debug("Added RAP CSS " + name
);
105 public String
getAdditionalHeaders() {
106 StringBuilder sb
= new StringBuilder();
107 if (headerCss
!= null) {
108 sb
.append("<style type='text/css'>\n");
109 sb
.append(headerCss
);
110 sb
.append("\n</style>\n");
112 for (String link
: fonts
) {
113 sb
.append("<link rel='stylesheet' href='");
117 if (sb
.length() == 0)
120 return sb
.toString();
123 void addStyleSheets(Bundle themeBundle
, ResourceLoader ssRL
) {
124 Enumeration
<URL
> themeResources
= themeBundle
.findEntries(cssPath
, "*.css", true);
125 if (themeResources
== null)
127 while (themeResources
.hasMoreElements()) {
128 String resource
= themeResources
.nextElement().getPath();
129 // remove first '/' so that RWT registers it
130 resource
= resource
.substring(1);
131 if (!resource
.endsWith("/")) {
132 if (css
.containsKey(resource
))
133 log
.warn("Overriding " + resource
+ " from " + themeBundle
.getSymbolicName());
134 css
.put(resource
, ssRL
);
141 void loadFontsUrl(URL url
) {
142 try (BufferedReader in
= new BufferedReader(new InputStreamReader(url
.openStream(), UTF_8
))) {
144 while ((line
= in
.readLine()) != null) {
146 if (!line
.equals("") && !line
.startsWith("#")) {
150 } catch (IOException e
) {
151 throw new CmsException("Cannot load URL " + url
, e
);
155 void addResources(BundleResourceLoader themeBRL
, String pattern
) {
156 Bundle themeBundle
= themeBRL
.getBundle();
157 Enumeration
<URL
> themeResources
= themeBundle
.findEntries(basePath
, pattern
, true);
158 if (themeResources
== null)
160 while (themeResources
.hasMoreElements()) {
161 String resource
= themeResources
.nextElement().getPath();
162 // remove first '/' so that RWT registers it
163 resource
= resource
.substring(1);
164 if (!resource
.endsWith("/")) {
165 if (resources
.containsKey(resource
))
166 log
.warn("Overriding " + resource
+ " from " + themeBundle
.getSymbolicName());
167 resources
.put(resource
, themeBRL
);
174 public String
getThemeId() {
178 public void setThemeId(String themeId
) {
179 this.themeId
= themeId
;
182 public String
getBasePath() {
186 public void setBasePath(String basePath
) {
187 this.basePath
= basePath
;
190 public String
getCssPath() {
194 public void setCssPath(String cssPath
) {
195 this.cssPath
= cssPath
;