]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.ui/src/org/argeo/cms/util/CmsTheme.java
[maven-release-plugin] prepare release argeo-commons-2.1.84
[lgpl/argeo-commons.git] / org.argeo.cms.ui / src / org / argeo / cms / util / CmsTheme.java
1 package org.argeo.cms.util;
2
3 import static java.nio.charset.StandardCharsets.UTF_8;
4
5 import java.io.BufferedReader;
6 import java.io.IOException;
7 import java.io.InputStreamReader;
8 import java.net.URL;
9 import java.util.ArrayList;
10 import java.util.Enumeration;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.stream.Collectors;
15
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;
24
25 /**
26 * Simplifies the theming of an app (only RAP is supported at this stage).<br>
27 *
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>
33 */
34 public class CmsTheme {
35 private final static Log log = LogFactory.getLog(CmsTheme.class);
36
37 private String themeId;
38 private Map<String, ResourceLoader> css = new HashMap<>();
39 private Map<String, ResourceLoader> resources = new HashMap<>();
40
41 private String headerCss;
42 private List<String> fonts = new ArrayList<>();
43
44 private String basePath;
45 private String cssPath;
46
47 public CmsTheme(BundleContext bundleContext) {
48 this(bundleContext, null);
49 }
50
51 public CmsTheme(BundleContext bundleContext, String symbolicName) {
52 Bundle themeBundle;
53 if (symbolicName == null) {
54 themeBundle = bundleContext.getBundle();
55 // basePath = "/theme/";
56 // cssPath = basePath;
57 } else {
58 themeBundle = ThemeUtils.findThemeBundle(bundleContext, symbolicName);
59 }
60 basePath = "/";
61 cssPath = "/rap/";
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");
71
72 // fonts
73 URL fontsUrl = themeBundle.getEntry(basePath + "fonts.txt");
74 if (fontsUrl != null) {
75 loadFontsUrl(fontsUrl);
76 }
77
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);
85 }
86 }
87
88 }
89
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);
97 }
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);
102 }
103 }
104
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");
111 }
112 for (String link : fonts) {
113 sb.append("<link rel='stylesheet' href='");
114 sb.append(link);
115 sb.append("'/>\n");
116 }
117 if (sb.length() == 0)
118 return null;
119 else
120 return sb.toString();
121 }
122
123 void addStyleSheets(Bundle themeBundle, ResourceLoader ssRL) {
124 Enumeration<URL> themeResources = themeBundle.findEntries(cssPath, "*.css", true);
125 if (themeResources == null)
126 return;
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);
135 }
136
137 }
138
139 }
140
141 void loadFontsUrl(URL url) {
142 try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) {
143 String line = null;
144 while ((line = in.readLine()) != null) {
145 line = line.trim();
146 if (!line.equals("") && !line.startsWith("#")) {
147 fonts.add(line);
148 }
149 }
150 } catch (IOException e) {
151 throw new CmsException("Cannot load URL " + url, e);
152 }
153 }
154
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)
159 return;
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);
168 }
169
170 }
171
172 }
173
174 public String getThemeId() {
175 return themeId;
176 }
177
178 public void setThemeId(String themeId) {
179 this.themeId = themeId;
180 }
181
182 public String getBasePath() {
183 return basePath;
184 }
185
186 public void setBasePath(String basePath) {
187 this.basePath = basePath;
188 }
189
190 public String getCssPath() {
191 return cssPath;
192 }
193
194 public void setCssPath(String cssPath) {
195 this.cssPath = cssPath;
196 }
197
198 }