Statistics
| Revision:

svn-gvsig-desktop / trunk / frameworks / _fwAndami / src / com / iver / andami / iconthemes / IconThemeManager.java @ 11513

History | View | Annotate | Download (13 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2007 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
package com.iver.andami.iconthemes;
43

    
44
import java.io.File;
45
import java.io.FileInputStream;
46
import java.io.FileNotFoundException;
47
import java.io.FilenameFilter;
48
import java.io.IOException;
49
import java.io.InputStream;
50
import java.net.MalformedURLException;
51
import java.util.ArrayList;
52
import java.util.Enumeration;
53
import java.util.zip.ZipEntry;
54
import java.util.zip.ZipException;
55
import java.util.zip.ZipFile;
56

    
57
import org.kxml2.io.KXmlParser;
58
import org.xmlpull.v1.XmlPullParserException;
59

    
60
import com.iver.andami.Launcher;
61
import com.iver.andami.PluginServices;
62

    
63
/**
64
 * <p>This class deals with icon themes, it understands the on-disk theme
65
 * format, it is able to list the availabe themes, to get the default
66
 * theme and to change it.</p>
67
 * 
68
 * <p>A XML theme description file should look similar to:
69
 * <pre>
70
 * &lt;?xml version="1.0" encoding="utf-8"?&gt;
71
 * &lt;theme&gt;
72
 *        &lt;name&gt;Default gvSIG icon theme&lt;/name&gt;
73
 *        &lt;description&gt;Clear fancy super great icon theme for gvSIG. Author: Salvador Dal?, &amp;lt;salvador.dali@art.org&amp;gt;&lt;/description&gt;
74
 *        &lt;version&gt;1.2&lt;/version&gt;
75
 * &lt;/theme&gt;
76
 * </pre>
77
 *   
78
 * 
79
 * @author Cesar Martinez Izquierdo <cesar.martinez@iver.es>
80
 *
81
 */
82
public class IconThemeManager {
83
        private File themesDir = null;
84
        private final String themeDefinitionFile = "theme.xml";
85
        private IconTheme defaultTheme = null;
86

    
87
        /**
88
         * Creates a new icon theme manager object, which will use
89
         * <code>basedir</code> as the directory
90
         * 
91
         * @param themesDir
92
         */
93
        public IconThemeManager(File themesDir) throws FileNotFoundException {
94
                if (!themesDir.exists())
95
                        throw new FileNotFoundException();
96
                this.themesDir = themesDir;        
97
        }
98

    
99
        
100
        
101
        public IconTheme get(String themeName) {
102
                IconThemeInfo[] themeList = list();
103
                for (int i=0; i<themeList.length; i++) {
104
                        if (themeList[i].getName().equals(themeName)) {
105
                                return get(themeList[i]);
106
                        }
107
                }
108
                return null;
109
        }
110
        
111
        public IconTheme get(IconThemeInfo themeInfo) {
112
                IconTheme theme = new IconTheme(themeInfo);
113
                if (themeInfo.getResource()==null) {
114
                        // no real theme was selected
115
                        return theme;
116
                }
117
                if (themeInfo.getResource() instanceof File) {
118
                        File basedir = (File) themeInfo.getResource();
119
                        if (basedir.isDirectory()) {
120
                                //TODO: crear el filtro de im?genes
121
                                File[] imageList = basedir.listFiles(new ImageFileFilter());
122
                                String name;
123
                                for (int i=imageList.length-1; i>=0; i--) {
124
                                        name = computeKey(imageList[i].getName());
125
                                        try {
126
                                                theme.register(name, imageList[i].toURL());
127
                                                System.out.println("registerning "+name+": "+imageList[i].toURL());
128
                                        } catch (MalformedURLException e) {}
129
                                }
130
                        }
131
                        else {
132
                                return null;
133
                        }
134
                }
135
                else if (themeInfo.getResource() instanceof ZipFile) {
136
                        ZipFile zipFile = (ZipFile) themeInfo.getResource();
137
                        ImageFileFilter filter = new ImageFileFilter();
138
                        Enumeration entries = zipFile.entries();
139
                        while (entries.hasMoreElements()) {
140
                                ZipEntry entry = (ZipEntry) entries.nextElement();
141
                                if (!entry.isDirectory() ) {
142
                                        if (filter.accept(new File(zipFile.getName()), entry.getName())) {
143
                                                theme.register(computeKey(entry.getName()), entry);
144
                                                System.out.println("registerning "+computeKey(entry.getName())+": "+entry.getName());
145
                                        }
146
                                }
147
                        }
148
                }
149
                return theme;
150
        }
151
        
152

    
153
        public IconTheme getDefault() {
154
                if (defaultTheme!=null) 
155
                        return defaultTheme;
156
                init();
157
                return defaultTheme;
158
        }
159
        
160
        public void init() {
161
                IconThemeInfo info = readSelectedFromAndamiConfig();
162
                defaultTheme = get(info);
163
        }
164
        
165

    
166
        
167
        public void setDefault(IconThemeInfo iconTheme) {
168
                /*
169
                 *  TODO Currently we just change it in AndamiConfig, so that on next
170
                 *  gvSIG restart the theme gets changed. However, we could implement
171
                 *  here a real on-the-fly theme change.
172
                 */
173
                saveSelectedInAndamiConfig(iconTheme);
174
        }
175
        
176
        public void setDefault(IconTheme iconTheme) {
177
                setDefault(iconTheme.getInfo());
178
        }
179
        
180
        /**
181
         * 
182
         * @return
183
         */
184
        public IconThemeInfo[] list() {
185
                File[] files = themesDir.listFiles();
186
                if (files==null) return null;
187
                
188
                ArrayList themeList = new ArrayList();
189
                IconThemeInfo info;
190
                for (int i=0; i<files.length; i++) {
191
                        if (files[i].isDirectory()) {
192
                                info = readInfoFromDir(files[i]);
193
                                if (info!=null)
194
                                        themeList.add(info);
195
                        }
196
                        else if (files[i].isFile()) { // ensure it's a regular file
197
                                try {
198
                                        info = readInfoFromZip(files[i]);
199
                                        themeList.add(info);
200
                                }
201
                                catch (ZipException ex) {
202
                                        PluginServices.getLogger().error("Error reading theme "+files[i].getPath()+". "+ex.getMessage());
203
                                }
204
                                catch (IOException ex) {
205
                                        PluginServices.getLogger().error("Error reading theme "+files[i].getPath()+". "+ex.getMessage());
206
                                }
207
                                        
208
                        }
209
                }
210
                
211
                return (IconThemeInfo[]) themeList.toArray(new IconThemeInfo[0]);
212
        }
213
        
214
        private IconThemeInfo readInfoFromDir(File dir){
215
                File themeDefinition = new File(dir + File.separator + themeDefinitionFile);
216
                IconThemeInfo themeInfo;
217
                try {
218
                        // try reading the XML file
219
                        if (themeDefinition.exists() && themeDefinition.isFile()) {
220
                                themeInfo = readXML(new FileInputStream(themeDefinition));
221
                                if (themeInfo.getDescription()==null)
222
                                        themeInfo.setDescription(dir.getName());
223
                                if (themeInfo.getName()==null)
224
                                        themeInfo.setName(themeInfo.getDescription());
225
                                themeInfo.setResource(dir);
226
                                return themeInfo;
227
                        }
228
                } catch (IOException e) {}
229
                catch (XmlPullParserException e) {
230
                        e.printStackTrace();
231
                }
232
                // the XML parsing failed, just show the dir name
233
                themeInfo = new IconThemeInfo();
234
                themeInfo.setName(dir.getName());
235
                themeInfo.setDescription(dir.getName());
236
                themeInfo.setResource(dir);
237
                return themeInfo;
238
        }
239
        
240
        private IconThemeInfo readXML(InputStream xmlStream) throws XmlPullParserException, IOException {
241
                KXmlParser parser = new KXmlParser();
242
                // we use null encoding, in this way kxml2 tries to detect the encoding                
243
                parser.setInput(xmlStream, null);
244
                IconThemeInfo themeInfo = new IconThemeInfo();
245
                for (parser.next(); parser.getEventType()!=KXmlParser.END_DOCUMENT; parser.next()) {
246
                        // este bucle externo recorre las etiquetas de primer y segundo nivel
247
                        if (parser.getEventType()==KXmlParser.START_TAG) {
248
                                if (parser.getName().equals("name")) {
249
                                        themeInfo.setName(parser.nextText());
250
                                }
251
                                else if (parser.getName().equals("description")) {
252
                                        themeInfo.setDescription(parser.nextText());
253
                                }
254
                                else if (parser.getName().equals("version")) {
255
                                        themeInfo.setVersion(parser.nextText());
256
                                }
257
                        }
258
                }
259
                return themeInfo;
260
        }
261
        
262
        
263
        private IconThemeInfo readInfoFromZip(File zipFile) throws ZipException, IOException {
264
                return readInfoFromZip(new ZipFile(zipFile));                
265
        }
266
        
267
        private IconThemeInfo readInfoFromZip(ZipFile zipFile) throws IOException {
268
                IconThemeInfo themeInfo;
269
                Enumeration entries = zipFile.entries();
270
                ZipEntry xmlEntry=null, dirEntry=null;
271
                // search for theme.xml and the directory names
272
                while (entries.hasMoreElements() && (xmlEntry==null||dirEntry==null)) {
273
                        ZipEntry entry = (ZipEntry) entries.nextElement();
274
                        if (entry.isDirectory()) {
275
                                dirEntry = entry;
276
                        }
277
                        if (basename(entry.getName()).equals(themeDefinitionFile)) {
278
                                xmlEntry = entry;
279
                        }
280
                }
281

    
282
                try {
283
                        // try with the XML file
284
                        if (xmlEntry!=null) {
285
                                themeInfo = readXML(zipFile.getInputStream(xmlEntry));
286
                                if (themeInfo.getDescription()==null)
287
                                        themeInfo.setDescription(zipFile.getName());
288
                                if (themeInfo.getName()==null)
289
                                        themeInfo.setName(themeInfo.getDescription());
290
                                themeInfo.setResource(zipFile);
291
                                return themeInfo;
292
                        }
293
                } catch (XmlPullParserException e) {
294
                        e.printStackTrace();
295
                        System.out.println(zipFile.getName());
296
                }
297

    
298
                themeInfo = new IconThemeInfo();
299
                themeInfo.setResource(zipFile);
300
                // now try with the directory
301
                if (dirEntry!=null) {                
302
                        themeInfo.setName(dirEntry.getName());
303
                        themeInfo.setDescription(dirEntry.getName());
304
                        return themeInfo;
305
                }
306
                else { // otherwise just use the zipName
307
                        themeInfo.setName(zipFile.getName());
308
                        themeInfo.setDescription(zipFile.getName());
309
                        return themeInfo;
310
                }
311
        }
312
        
313
        private String basename(String fullname) {
314
                String[] parts = fullname.split(File.separator+"|/");
315
                return parts[parts.length-1];
316
        }
317
        
318
        public File getThemesDir() {
319
                return themesDir;
320
        }
321
        
322
        public void setThemesDir(File themesDir) {
323
                this.themesDir = themesDir;
324
        }
325
        
326
        private IconThemeInfo readSelectedFromAndamiConfig() {
327
                com.iver.andami.config.generate.IconTheme selectedTheme = null;
328
                if (Launcher.getAndamiConfig().getAndamiOptions()!=null && Launcher.getAndamiConfig().getAndamiOptions().getIconTheme()!=null)
329
                        selectedTheme = Launcher.getAndamiConfig().getAndamiOptions().getIconTheme();
330
                IconThemeInfo info;
331
                if (selectedTheme==null) {
332
                        // there will be no theme, just create some values
333
                        info = new IconThemeInfo();
334
                        info.setName("No theme loaded");
335
                        info.setResource(null); // null resource means that no real theme is loaded
336
                        info.setDescription("No theme loaded");
337
                        info.setVersion("0");
338
                        setThemesDir(new File("iconThemes"));
339
                }
340
                else if (selectedTheme.getResource()!=null) {
341
                        try {
342
                                // try to load a ZIPPED theme
343
                                ZipFile zipfile = new ZipFile(selectedTheme.getResource());
344
                                info = readInfoFromZip(zipfile);
345
                        } catch (ZipException e) {
346
                                // ZIPPED theme failed, try to load from directory
347
                                info = readInfoFromDir(new File(selectedTheme.getResource()));
348
                        } catch (IOException e) {
349
                                // ZIPPED theme failed, try to load from directory
350
                                info = readInfoFromDir(new File(selectedTheme.getResource()));
351
                        }
352
                        if (selectedTheme.getBasedir()!=null)
353
                                setThemesDir(new File(selectedTheme.getBasedir()));
354
                        else
355
                                setThemesDir(new File("iconThemes"));
356
                }
357
                else {
358
                        // just set the values that were selected (even if they don't map to a real theme)
359
                        info = new IconThemeInfo();
360
                        if (selectedTheme.getName()!=null)
361
                                info.setName(selectedTheme.getName());
362
                        else
363
                                info.setName("No theme loaded");
364
                        info.setResource(null); // null resource means that no real theme is loaded
365
                        if (selectedTheme.getName()!=null)
366
                                info.setDescription(selectedTheme.getDescription());
367
                        else
368
                                info.setDescription("No theme loaded");
369
                        if (selectedTheme.getVersion()!=null)
370
                                info.setVersion(selectedTheme.getVersion());
371
                        else
372
                                info.setVersion("0");
373
                        if (selectedTheme.getBasedir()!=null)
374
                                setThemesDir(new File(selectedTheme.getBasedir()));
375
                        else
376
                                setThemesDir(new File("iconThemes"));
377
                        
378
                }
379
                return info;
380
        }
381
        
382
        private void saveSelectedInAndamiConfig(IconThemeInfo selectedTheme) {
383
                com.iver.andami.config.generate.AndamiOptions options = Launcher.getAndamiConfig().getAndamiOptions();
384
                if (options==null) {
385
                        options = new com.iver.andami.config.generate.AndamiOptions();
386
                }
387
                com.iver.andami.config.generate.IconTheme themeConfig = options.getIconTheme();
388
                if (themeConfig==null) {
389
                        themeConfig = new com.iver.andami.config.generate.IconTheme(); 
390
                }
391
                themeConfig.setName(selectedTheme.getName());
392
                themeConfig.setDescription(selectedTheme.getDescription());
393
                themeConfig.setVersion(selectedTheme.getVersion());
394
                if (selectedTheme.getResource()!=null) {
395
                        if (selectedTheme.getResource() instanceof File) {
396
                                File resource = (File) selectedTheme.getResource();
397
                                themeConfig.setResource(resource.getName());                                
398
                        }
399
                        else if (selectedTheme.getResource() instanceof ZipFile) {
400
                                ZipFile resource = (ZipFile) selectedTheme.getResource();
401
                                themeConfig.setResource(resource.getName());                                
402
                        }
403
                }
404
        }
405
        
406
        class ImageFileFilter implements FilenameFilter {
407
                public boolean accept(File dir, String fileName) {
408
                        String extension = "";
409
                        int pointPos = fileName.lastIndexOf(".");
410
                        if (pointPos>0 && pointPos < (fileName.length()-1) )
411
                                extension = fileName.substring(pointPos+1).toLowerCase();
412
                        if ( extension.equals("jpg") || extension.equals("jpeg")
413
                                        || extension.equals("png")
414
                                        || extension.equals("gif")
415
                                        
416
                                        )
417
                                return true;
418
                        else
419
                                return false;
420
                }
421
        }
422
        
423
        private String computeKey(String fileName) {
424
                int pointPos = fileName.lastIndexOf(".");
425
                if (pointPos!=-1)
426
                        return fileName.substring(0, pointPos);
427
                else
428
                        return fileName;
429
        }
430
}