]> git.argeo.org Git - lgpl/argeo-commons.git/blob - Theme.java
3fa4bc451edae6b324603c5a0dadf5840a1e6bbe
[lgpl/argeo-commons.git] / Theme.java
1 package org.argeo.cms.script;
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.argeo.cms.util.BundleResourceLoader;
20 import org.argeo.cms.util.ThemeUtils;
21 import org.eclipse.rap.rwt.application.Application;
22 import org.eclipse.rap.rwt.service.ResourceLoader;
23 import org.osgi.framework.Bundle;
24 import org.osgi.framework.BundleContext;
25
26 public class Theme {
27 private final static Log log = LogFactory.getLog(Theme.class);
28
29 private final String themeId;
30 private Map<String, ResourceLoader> css = new HashMap<>();
31 private Map<String, ResourceLoader> resources = new HashMap<>();
32
33 private String headerCss;
34 private List<String> fonts = new ArrayList<>();
35
36 private String basePath;
37 private String cssPath;
38
39 public Theme(BundleContext bundleContext) {
40 this(bundleContext, null);
41 }
42
43 public Theme(BundleContext bundleContext, String symbolicName) {
44 Bundle themeBundle;
45 if (symbolicName == null) {
46 themeBundle = bundleContext.getBundle();
47 basePath = "/theme/internal/";
48 cssPath = basePath;
49 } else {
50 themeBundle = ThemeUtils.findThemeBundle(bundleContext, symbolicName);
51 basePath = "/";
52 cssPath = "/rap/";
53 }
54 this.themeId = themeBundle.getSymbolicName();
55 addStyleSheets(themeBundle, new BundleResourceLoader(themeBundle));
56 BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
57 addResources(themeBRL, "*.png");
58 addResources(themeBRL, "*.gif");
59 addResources(themeBRL, "*.jpg");
60 addResources(themeBRL, "*.jpeg");
61 addResources(themeBRL, "*.svg");
62 addResources(themeBRL, "*.ico");
63
64 // fonts
65 URL fontsUrl = themeBundle.getEntry(basePath + "fonts.txt");
66 if (fontsUrl != null) {
67 loadFontsUrl(fontsUrl);
68 }
69
70 // common CSS header (plain CSS)
71 URL headerCssUrl = themeBundle.getEntry(basePath + "header.css");
72 if (headerCssUrl != null) {
73 try (BufferedReader buffer = new BufferedReader(new InputStreamReader(headerCssUrl.openStream(), UTF_8))) {
74 headerCss = buffer.lines().collect(Collectors.joining("\n"));
75 } catch (IOException e) {
76 throw new CmsException("Cannot read " + headerCssUrl, e);
77 }
78 }
79
80 }
81
82 public void apply(Application application) {
83 for (String name : resources.keySet()) {
84 application.addResource(name, resources.get(name));
85 if (log.isDebugEnabled())
86 log.debug("Added resource " + name);
87 }
88 for (String name : css.keySet()) {
89 application.addStyleSheet(themeId, name, css.get(name));
90 if (log.isDebugEnabled())
91 log.debug("Added RAP CSS " + name);
92 }
93 }
94
95 public String getAdditionalHeaders() {
96 StringBuilder sb = new StringBuilder();
97 if (headerCss != null) {
98 sb.append("<style type='text/css'>\n");
99 sb.append(headerCss);
100 sb.append("\n</style>\n");
101 }
102 for (String link : fonts) {
103 sb.append("<link rel='stylesheet' href='");
104 sb.append(link);
105 sb.append("'/>\n");
106 }
107 if (sb.length() == 0)
108 return null;
109 else
110 return sb.toString();
111 }
112
113 void addStyleSheets(Bundle themeBundle, ResourceLoader ssRL) {
114 Enumeration<URL> themeResources = themeBundle.findEntries(cssPath, "*.css", true);
115 if (themeResources == null)
116 return;
117 while (themeResources.hasMoreElements()) {
118 String resource = themeResources.nextElement().getPath();
119 // remove first '/' so that RWT registers it
120 resource = resource.substring(1);
121 if (!resource.endsWith("/")) {
122 if (css.containsKey(resource))
123 log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
124 css.put(resource, ssRL);
125 }
126
127 }
128
129 }
130
131 void loadFontsUrl(URL url) {
132 try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) {
133 String line = null;
134 while ((line = in.readLine()) != null) {
135 line = line.trim();
136 if (!line.equals("") && !line.startsWith("#")) {
137 fonts.add(line);
138 }
139 }
140 } catch (IOException e) {
141 throw new CmsException("Cannot load URL " + url, e);
142 }
143 }
144
145 void addResources(BundleResourceLoader themeBRL, String pattern) {
146 Bundle themeBundle = themeBRL.getBundle();
147 Enumeration<URL> themeResources = themeBundle.findEntries(basePath, pattern, true);
148 if (themeResources == null)
149 return;
150 while (themeResources.hasMoreElements()) {
151 String resource = themeResources.nextElement().getPath();
152 // remove first '/' so that RWT registers it
153 resource = resource.substring(1);
154 if (!resource.endsWith("/")) {
155 if (resources.containsKey(resource))
156 log.warn("Overriding " + resource + " from " + themeBundle.getSymbolicName());
157 resources.put(resource, themeBRL);
158 }
159
160 }
161
162 }
163
164 public String getThemeId() {
165 return themeId;
166 }
167
168 public String getBasePath() {
169 return basePath;
170 }
171
172 public void setBasePath(String basePath) {
173 this.basePath = basePath;
174 }
175
176 public String getCssPath() {
177 return cssPath;
178 }
179
180 public void setCssPath(String cssPath) {
181 this.cssPath = cssPath;
182 }
183
184 }