Crossfire JXClient, Trunk  R20561
Settings.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.settings;
23 
26 import java.io.BufferedWriter;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.io.InputStreamReader;
33 import java.io.LineNumberReader;
34 import java.io.OutputStreamWriter;
35 import java.util.Map;
36 import java.util.TreeMap;
37 import org.jetbrains.annotations.NotNull;
38 
43 public class Settings {
44 
48  @NotNull
49  private final File file;
50 
54  @NotNull
55  private final Map<String, Entry> values = new TreeMap<>();
56 
60  private boolean noSave = true;
61 
66  public Settings(@NotNull final File file) {
67  this.file = file;
68  loadValues();
69  noSave = false;
70  }
71 
78  @NotNull
79  public String getString(@NotNull final SettingsEntry<?> key) {
80  final Entry entry = values.get(key.getKey());
81  return entry == null ? key.getDefaultValue().toString() : entry.getValue();
82  }
83 
90  public boolean getBoolean(@NotNull final SettingsEntry<Boolean> key) {
91  final String value = getString(key);
92  try {
93  return Boolean.parseBoolean(value);
94  } catch (final NumberFormatException ignored) {
95  return key.getDefaultValue();
96  }
97  }
98 
105  public int getInt(@NotNull final SettingsEntry<Integer> key) {
106  return NumberParser.parseInt(getString(key), key.getDefaultValue());
107  }
108 
115  public long getLong(@NotNull final SettingsEntry<Long> key) {
116  return NumberParser.parseLong(getString(key), key.getDefaultValue());
117  }
118 
124  public void putString(@NotNull final SettingsEntry<?> key, @NotNull final String value) {
125  final Entry oldEntry = values.get(key.getKey());
126  if (oldEntry == null) {
127  values.put(key.getKey(), new Entry(value, key.getComment()));
128  } else {
129  oldEntry.setDocumentation(key.getComment());
130  if (!oldEntry.getValue().equals(value)) {
131  oldEntry.setValue(value);
132  setChanged();
133  }
134  }
135  }
136 
142  public void putBoolean(@NotNull final SettingsEntry<Boolean> key, final boolean value) {
143  putString(key, Boolean.toString(value));
144  }
145 
151  public void putInt(@NotNull final SettingsEntry<Integer> key, final int value) {
152  putString(key, Integer.toString(value));
153  }
154 
160  public void putLong(@NotNull final SettingsEntry<Long> key, final long value) {
161  putString(key, Long.toString(value));
162  }
163 
168  public void remove(@NotNull final String key) {
169  if (values.remove(key) != null) {
170  setChanged();
171  }
172  }
173 
178  private void setChanged() {
179  if (noSave) {
180  return;
181  }
182 
183  try {
184  saveValues();
185  } catch (final IOException ex) {
186  System.err.println(file+": "+ex.getMessage());
187  }
188  }
189 
193  private void loadValues() {
194  values.clear();
195 
196  try {
197  try (final FileInputStream fis = new FileInputStream(file)) {
198  try (final InputStreamReader isr = new InputStreamReader(fis, "UTF-8")) {
199  try (final LineNumberReader lnr = new LineNumberReader(isr)) {
200  loadValues(lnr);
201  }
202  }
203  }
204  } catch (final FileNotFoundException ignored) {
205  // ignore
206  } catch (final IOException ex) {
207  System.err.println(file+": "+ex.getMessage());
208  }
209  }
210 
216  private void loadValues(@NotNull final LineNumberReader lnr) throws IOException {
217  while (true) {
218  final String line2 = lnr.readLine();
219  if (line2 == null) {
220  break;
221  }
222  final String line = Codec.decode(line2.trim());
223  if (line.startsWith("#") || line.isEmpty()) {
224  continue;
225  }
226 
227  final String[] tmp = line.split("=", 2);
228  if (tmp.length != 2) {
229  System.err.println(file+":"+lnr.getLineNumber()+": syntax error");
230  continue;
231  }
232  final String key = tmp[0];
233  final String value = tmp[1];
234 
235  putString(new SettingsEntry<>(key, "", null), value);
236  }
237  }
238 
243  private void saveValues() throws IOException {
244  final File tmpFile = new File(file.getPath()+".tmp");
245  try (final FileOutputStream fos = new FileOutputStream(tmpFile)) {
246  try (final OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8")) {
247  try (final BufferedWriter bw = new BufferedWriter(osw)) {
248  saveNode(bw, values);
249  }
250  }
251  }
252 
253  if (!tmpFile.renameTo(file)) {
254  throw new IOException("cannot rename "+tmpFile+" to "+file);
255  }
256  }
257 
264  private static void saveNode(@NotNull final BufferedWriter writer, @NotNull final Map<String, Entry> node) throws IOException {
265  if (node.isEmpty()) {
266  return;
267  }
268 
269  for (final Map.Entry<String, Entry> entry : node.entrySet()) {
270  final Entry value = entry.getValue();
271 
272  writer.newLine();
273 
274  final String documentation = value.getDocumentation();
275  if (documentation != null) {
276  writer.write("# ");
277  writer.write(Codec.encode(documentation));
278  writer.newLine();
279  }
280 
281  writer.write(Codec.encode(entry.getKey()));
282  writer.write("=");
283  writer.write(Codec.encode(value.getValue()));
284  writer.newLine();
285  }
286  }
287 
288 }
void putBoolean(@NotNull final SettingsEntry< Boolean > key, final boolean value)
Stores a key/value pair.
Definition: Settings.java:142
long getLong(@NotNull final SettingsEntry< Long > key)
Returns the long associated with the specified key at a node or.
Definition: Settings.java:115
boolean noSave
Flag to inhibit saving.
Definition: Settings.java:60
static long parseLong(@NotNull final String string, final long defaultValue)
Converts a string into a long value.
void putInt(@NotNull final SettingsEntry< Integer > key, final int value)
Stores a key/value pair.
Definition: Settings.java:151
final File file
The file for loading/saving values.
Definition: Settings.java:49
void loadValues(@NotNull final LineNumberReader lnr)
Loads the values.
Definition: Settings.java:216
boolean getBoolean(@NotNull final SettingsEntry< Boolean > key)
Returns the boolean associated with the specified key at a node or.
Definition: Settings.java:90
void putLong(@NotNull final SettingsEntry< Long > key, final long value)
Stores a key/value pair.
Definition: Settings.java:160
static String encode(@NotNull final String str)
Encodes a string to make it fit into one line.
Definition: Codec.java:92
String getDocumentation()
Returns the documentation string.
Definition: Entry.java:77
final Map< String, Entry > values
The stored values.
Definition: Settings.java:55
The value part of an entry of a settings file.
Definition: Entry.java:31
Maintains a set of key/value pairs.
Definition: Settings.java:43
static void saveNode(@NotNull final BufferedWriter writer, @NotNull final Map< String, Entry > node)
Saves one node.
Definition: Settings.java:264
void setValue(@NotNull final String value)
Sets the value.
Definition: Entry.java:68
void loadValues()
Loads the values from the backing file.
Definition: Settings.java:193
void saveValues()
Saves the values to the backing file.
Definition: Settings.java:243
static int parseInt(@NotNull final String string, final int defaultValue)
Converts a string into an int value.
int getInt(@NotNull final SettingsEntry< Integer > key)
Returns the integer associated with the specified key at a node or.
Definition: Settings.java:105
static String decode(@NotNull final String str)
Decodes a string which was encoded by encode(String).
Definition: Codec.java:108
Utility class to encode arbitrary Strings to fit in a single text line.
Definition: Codec.java:35
void setDocumentation(@Nullable final String documentation)
Sets the documentation string.
Definition: Entry.java:85
Utility class for parsing strings into numbers.
void putString(@NotNull final SettingsEntry<?> key, @NotNull final String value)
Stores a key/value pair.
Definition: Settings.java:124
String getValue()
Returns the value.
Definition: Entry.java:60
Settings(@NotNull final File file)
Creates a new instance.
Definition: Settings.java:66
void setChanged()
This function is called whenever the contents of values has changed.
Definition: Settings.java:178
String getString(@NotNull final SettingsEntry<?> key)
Returns the string associated with the specified key at a node, or.
Definition: Settings.java:79