1 /*
2  * Copyright (c) 2008-2019 Emmanuel Dupuy.
3  * This project is distributed under the GPLv3 license.
4  * This is a Copyleft license that gives the user the right to use,
5  * copy and modify the code freely for non-commercial purposes.
6  */
7 
8 package org.jd.gui.service.configuration;
9 
10 import org.jd.gui.Constants;
11 import org.jd.gui.model.configuration.Configuration;
12 import org.jd.gui.service.platform.PlatformService;
13 import org.jd.gui.util.exception.ExceptionUtil;
14 
15 import javax.swing.*;
16 import javax.xml.stream.*;
17 import java.awt.*;
18 import java.io.*;
19 import java.net.URL;
20 import java.util.*;
21 import java.util.List;
22 import java.util.jar.Manifest;
23 
24 public class ConfigurationXmlPersisterProvider implements ConfigurationPersister {
25     protected static final String ERROR_BACKGROUND_COLOR = "JdGuiPreferences.errorBackgroundColor";
26     protected static final String JD_CORE_VERSION = "JdGuiPreferences.jdCoreVersion";
27 
28     protected static final File FILE = getConfigFile();
29 
getConfigFile()30     protected static File getConfigFile() {
31         String configFilePath = System.getProperty(Constants.CONFIG_FILENAME);
32 
33         if (configFilePath != null) {
34             File configFile = new File(configFilePath);
35             if (configFile.exists()) {
36                 return configFile;
37             }
38         }
39 
40         if (PlatformService.getInstance().isLinux()) {
41             // See: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
42             String xdgConfigHome = System.getenv("XDG_CONFIG_HOME");
43             if (xdgConfigHome != null) {
44                 File xdgConfigHomeFile = new File(xdgConfigHome);
45                 if (xdgConfigHomeFile.exists()) {
46                     return new File(xdgConfigHomeFile, Constants.CONFIG_FILENAME);
47                 }
48             }
49 
50             File userConfigFile = new File(System.getProperty("user.home"), ".config");
51             if (userConfigFile.exists()) {
52                 return new File(userConfigFile, Constants.CONFIG_FILENAME);
53             }
54         } else if (PlatformService.getInstance().isWindows()) {
55             // See: http://blogs.msdn.com/b/patricka/archive/2010/03/18/where-should-i-store-my-data-and-configuration-files-if-i-target-multiple-os-versions.aspx
56             String roamingConfigHome = System.getenv("APPDATA");
57             if (roamingConfigHome != null) {
58                 File roamingConfigHomeFile = new File(roamingConfigHome);
59                 if (roamingConfigHomeFile.exists()) {
60                     return new File(roamingConfigHomeFile, Constants.CONFIG_FILENAME);
61                 }
62             }
63         }
64 
65         return new File(Constants.CONFIG_FILENAME);
66     }
67 
68     @Override
load()69     public Configuration load() {
70         // Default values
71         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
72 
73         int w = (screenSize.width>Constants.DEFAULT_WIDTH) ? Constants.DEFAULT_WIDTH : screenSize.width;
74         int h = (screenSize.height>Constants.DEFAULT_HEIGHT) ? Constants.DEFAULT_HEIGHT : screenSize.height;
75         int x = (screenSize.width-w)/2;
76         int y = (screenSize.height-h)/2;
77 
78         Configuration config = new Configuration();
79         config.setMainWindowLocation(new Point(x, y));
80         config.setMainWindowSize(new Dimension(w, h));
81         config.setMainWindowMaximize(false);
82 
83         String defaultLaf = System.getProperty("swing.defaultlaf");
84 
85         config.setLookAndFeel((defaultLaf != null) ? defaultLaf : UIManager.getSystemLookAndFeelClassName());
86 
87         File recentSaveDirectory = new File(System.getProperty("user.dir"));
88 
89         config.setRecentLoadDirectory(recentSaveDirectory);
90         config.setRecentSaveDirectory(recentSaveDirectory);
91 
92         if (FILE.exists()) {
93             try (FileInputStream fis = new FileInputStream(FILE)) {
94                 XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(fis);
95 
96                 // Load values
97                 String name = "";
98                 Stack<String> names = new Stack<>();
99                 List<File> recentFiles = new ArrayList<>();
100                 boolean maximize = false;
101                 Map<String, String> preferences = config.getPreferences();
102 
103                 while (reader.hasNext()) {
104                     switch (reader.next()) {
105                         case XMLStreamConstants.START_ELEMENT:
106                             names.push(name);
107                             name += '/' + reader.getLocalName();
108                             switch (name) {
109                                 case "/configuration/gui/mainWindow/location":
110                                     x = Integer.parseInt(reader.getAttributeValue(null, "x"));
111                                     y = Integer.parseInt(reader.getAttributeValue(null, "y"));
112                                     break;
113                                 case "/configuration/gui/mainWindow/size":
114                                     w = Integer.parseInt(reader.getAttributeValue(null, "w"));
115                                     h = Integer.parseInt(reader.getAttributeValue(null, "h"));
116                                     break;
117                             }
118                             break;
119                         case XMLStreamConstants.END_ELEMENT:
120                             name = names.pop();
121                             break;
122                         case XMLStreamConstants.CHARACTERS:
123                             switch (name) {
124                                 case "/configuration/recentFilePaths/filePath":
125                                     File file = new File(reader.getText().trim());
126                                     if (file.exists()) {
127                                         recentFiles.add(file);
128                                     }
129                                     break;
130                                 case "/configuration/recentDirectories/loadPath":
131                                     file = new File(reader.getText().trim());
132                                     if (file.exists()) {
133                                         config.setRecentLoadDirectory(file);
134                                     }
135                                     break;
136                                 case "/configuration/recentDirectories/savePath":
137                                     file = new File(reader.getText().trim());
138                                     if (file.exists()) {
139                                         config.setRecentSaveDirectory(file);
140                                     }
141                                     break;
142                                 case "/configuration/gui/lookAndFeel":
143                                     config.setLookAndFeel(reader.getText().trim());
144                                     break;
145                                 case "/configuration/gui/mainWindow/maximize":
146                                     maximize = Boolean.parseBoolean(reader.getText().trim());
147                                     break;
148                                 default:
149                                     if (name.startsWith("/configuration/preferences/")) {
150                                         String key = name.substring("/configuration/preferences/".length());
151                                         preferences.put(key, reader.getText().trim());
152                                     }
153                                     break;
154                             }
155                             break;
156                     }
157                 }
158 
159                 if (recentFiles.size() > Constants.MAX_RECENT_FILES) {
160                     // Truncate
161                     recentFiles = recentFiles.subList(0, Constants.MAX_RECENT_FILES);
162                 }
163                 config.setRecentFiles(recentFiles);
164 
165                 if ((x >= 0) && (y >= 0) && (x + w < screenSize.width) && (y + h < screenSize.height)) {
166                     // Update preferences
167                     config.setMainWindowLocation(new Point(x, y));
168                     config.setMainWindowSize(new Dimension(w, h));
169                     config.setMainWindowMaximize(maximize);
170                 }
171 
172                 reader.close();
173             } catch (Exception e) {
174                 assert ExceptionUtil.printStackTrace(e);
175             }
176         }
177 
178         if (! config.getPreferences().containsKey(ERROR_BACKGROUND_COLOR)) {
179             config.getPreferences().put(ERROR_BACKGROUND_COLOR, "0xFF6666");
180         }
181 
182         config.getPreferences().put(JD_CORE_VERSION, getJdCoreVersion());
183 
184         return config;
185     }
186 
getJdCoreVersion()187     protected String getJdCoreVersion() {
188         try {
189             Enumeration<URL> enumeration = ConfigurationXmlPersisterProvider.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
190 
191             while (enumeration.hasMoreElements()) {
192                 try (InputStream is = enumeration.nextElement().openStream()) {
193                     String attribute = new Manifest(is).getMainAttributes().getValue("JD-Core-Version");
194                     if (attribute != null) {
195                         return attribute;
196                     }
197                 }
198             }
199         } catch (IOException e) {
200             assert ExceptionUtil.printStackTrace(e);
201         }
202 
203         return "SNAPSHOT";
204     }
205 
206     @Override
save(Configuration configuration)207     public void save(Configuration configuration) {
208         Point l = configuration.getMainWindowLocation();
209         Dimension s = configuration.getMainWindowSize();
210 
211         try (FileOutputStream fos = new FileOutputStream(FILE)) {
212             XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(fos);
213 
214             // Save values
215             writer.writeStartDocument();
216             writer.writeCharacters("\n");
217             writer.writeStartElement("configuration");
218             writer.writeCharacters("\n\t");
219 
220             writer.writeStartElement("gui");
221             writer.writeCharacters("\n\t\t");
222                 writer.writeStartElement("mainWindow");
223                 writer.writeCharacters("\n\t\t\t");
224                     writer.writeStartElement("location");
225                         writer.writeAttribute("x", String.valueOf(l.x));
226                         writer.writeAttribute("y", String.valueOf(l.y));
227                     writer.writeEndElement();
228                     writer.writeCharacters("\n\t\t\t");
229                     writer.writeStartElement("size");
230                         writer.writeAttribute("w", String.valueOf(s.width));
231                         writer.writeAttribute("h", String.valueOf(s.height));
232                     writer.writeEndElement();
233                     writer.writeCharacters("\n\t\t\t");
234                     writer.writeStartElement("maximize");
235                         writer.writeCharacters(String.valueOf(configuration.isMainWindowMaximize()));
236                     writer.writeEndElement();
237                     writer.writeCharacters("\n\t\t");
238                 writer.writeEndElement();
239                 writer.writeCharacters("\n\t\t");
240                 writer.writeStartElement("lookAndFeel");
241                     writer.writeCharacters(configuration.getLookAndFeel());
242                 writer.writeEndElement();
243                 writer.writeCharacters("\n\t");
244             writer.writeEndElement();
245             writer.writeCharacters("\n\t");
246 
247             writer.writeStartElement("recentFilePaths");
248 
249             for (File recentFile : configuration.getRecentFiles()) {
250                 writer.writeCharacters("\n\t\t");
251                 writer.writeStartElement("filePath");
252                     writer.writeCharacters(recentFile.getAbsolutePath());
253                 writer.writeEndElement();
254             }
255 
256             writer.writeCharacters("\n\t");
257             writer.writeEndElement();
258             writer.writeCharacters("\n\t");
259 
260             writer.writeStartElement("recentDirectories");
261             writer.writeCharacters("\n\t\t");
262                 writer.writeStartElement("loadPath");
263                     writer.writeCharacters(configuration.getRecentLoadDirectory().getAbsolutePath());
264                 writer.writeEndElement();
265                 writer.writeCharacters("\n\t\t");
266                 writer.writeStartElement("savePath");
267                     writer.writeCharacters(configuration.getRecentSaveDirectory().getAbsolutePath());
268                 writer.writeEndElement();
269                 writer.writeCharacters("\n\t");
270             writer.writeEndElement();
271             writer.writeCharacters("\n\t");
272 
273             writer.writeStartElement("preferences");
274 
275             for (Map.Entry<String, String> preference : configuration.getPreferences().entrySet()) {
276                 writer.writeCharacters("\n\t\t");
277                 writer.writeStartElement(preference.getKey());
278                     writer.writeCharacters(preference.getValue());
279                 writer.writeEndElement();
280             }
281 
282             writer.writeCharacters("\n\t");
283             writer.writeEndElement();
284             writer.writeCharacters("\n");
285 
286             writer.writeEndElement();
287             writer.writeEndDocument();
288             writer.close();
289         } catch (Exception e) {
290             assert ExceptionUtil.printStackTrace(e);
291         }
292     }
293 }
294