Skip to content

Commit 9aadece

Browse files
authored
Add simulator auto bundle tests (#4045)
Fixed #4032
1 parent c80051e commit 9aadece

File tree

2 files changed

+385
-1
lines changed

2 files changed

+385
-1
lines changed

Ports/JavaSE/src/com/codename1/impl/javase/JavaSEPort.java

Lines changed: 287 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,15 @@ public class JavaSEPort extends CodenameOneImplementation {
188188

189189

190190
private static final int ICON_SIZE=24;
191+
private static final String PREF_AUTO_UPDATE_DEFAULT_BUNDLE = "cn1.autoDefaultResourceBundle";
191192
public final static boolean IS_MAC;
192193
private static boolean isIOS;
193194
public static boolean blockNativeBrowser;
194195
private static final boolean isWindows;
195196
private static String fontFaceSystem;
196197
private Boolean darkMode;
198+
private AutoLocalizationBundle autoLocalizationBundle;
199+
private boolean autoUpdateDefaultResourceBundle;
197200

198201
/**
199202
* @return the fullScreen
@@ -227,6 +230,12 @@ private JFrame findTopFrame() {
227230
@Override
228231
public boolean isFullScreenSupported() {
229232
Preferences pref = Preferences.userNodeForPackage(JavaSEPort.class);
233+
autoUpdateDefaultResourceBundle = pref.getBoolean(PREF_AUTO_UPDATE_DEFAULT_BUNDLE, false);
234+
if (autoUpdateDefaultResourceBundle) {
235+
enableAutoLocalizationBundle();
236+
} else {
237+
disableAutoLocalizationBundle();
238+
}
230239
boolean desktopSkin = pref.getBoolean("desktopSkin", false);
231240
if (isSimulator() && !desktopSkin) {
232241
return false;
@@ -3484,6 +3493,24 @@ public void itemStateChanged(ItemEvent e) {
34843493
});
34853494
simulatorMenu.add(useAppFrameMenu);
34863495

3496+
final JCheckBoxMenuItem autoLocalizationMenu = new JCheckBoxMenuItem("Auto Update Default Bundle");
3497+
autoLocalizationMenu.setSelected(autoUpdateDefaultResourceBundle);
3498+
autoLocalizationMenu.addItemListener(new ItemListener() {
3499+
3500+
@Override
3501+
public void itemStateChanged(ItemEvent e) {
3502+
boolean selected = autoLocalizationMenu.isSelected();
3503+
autoUpdateDefaultResourceBundle = selected;
3504+
pref.putBoolean(PREF_AUTO_UPDATE_DEFAULT_BUNDLE, selected);
3505+
if (selected) {
3506+
enableAutoLocalizationBundle();
3507+
} else {
3508+
disableAutoLocalizationBundle();
3509+
}
3510+
}
3511+
});
3512+
simulatorMenu.add(autoLocalizationMenu);
3513+
34873514
final JCheckBoxMenuItem zoomMenu = new JCheckBoxMenuItem("Zoom", scrollableSkin);
34883515
if (appFrame == null) simulatorMenu.add(zoomMenu);
34893516

@@ -5281,6 +5308,12 @@ public void init(Object m) {
52815308
}*/
52825309

52835310
Preferences pref = Preferences.userNodeForPackage(JavaSEPort.class);
5311+
autoUpdateDefaultResourceBundle = pref.getBoolean(PREF_AUTO_UPDATE_DEFAULT_BUNDLE, false);
5312+
if (autoUpdateDefaultResourceBundle) {
5313+
enableAutoLocalizationBundle();
5314+
} else {
5315+
disableAutoLocalizationBundle();
5316+
}
52845317
boolean desktopSkin = pref.getBoolean("desktopSkin", false);
52855318
if (desktopSkin && m == null) {
52865319
safeAreaLandscape = null;
@@ -13623,7 +13656,260 @@ public Boolean canExecute(String url) {
1362313656
return super.canExecute(url);
1362413657
}
1362513658

13626-
13659+
13660+
private void enableAutoLocalizationBundle() {
13661+
File bundleFile = findDefaultLocalizationBundleFile();
13662+
if (bundleFile == null) {
13663+
return;
13664+
}
13665+
Map<String, String> current = UIManager.getInstance().getBundle();
13666+
if (current instanceof AutoLocalizationBundle) {
13667+
AutoLocalizationBundle existing = (AutoLocalizationBundle) current;
13668+
if (existing.isForFile(bundleFile)) {
13669+
autoLocalizationBundle = existing;
13670+
existing.ensureFileExists();
13671+
return;
13672+
}
13673+
}
13674+
AutoLocalizationBundle newBundle = new AutoLocalizationBundle(bundleFile, current);
13675+
autoLocalizationBundle = newBundle;
13676+
UIManager.getInstance().setBundle(newBundle);
13677+
}
13678+
13679+
private void disableAutoLocalizationBundle() {
13680+
Map<String, String> current = UIManager.getInstance().getBundle();
13681+
if (current instanceof AutoLocalizationBundle) {
13682+
AutoLocalizationBundle existing = (AutoLocalizationBundle) current;
13683+
Map<String, String> snapshot = new HashMap<String, String>(existing);
13684+
UIManager.getInstance().setBundle(snapshot);
13685+
}
13686+
autoLocalizationBundle = null;
13687+
}
13688+
13689+
private File findDefaultLocalizationBundleFile() {
13690+
File localizationDir = findLocalizationDirectory();
13691+
if (localizationDir == null) {
13692+
return null;
13693+
}
13694+
java.util.List<File> bundles = new java.util.ArrayList<File>();
13695+
collectLocalizationBundles(localizationDir, bundles);
13696+
File preferred = new File(localizationDir, "Bundle.properties");
13697+
if (preferred.exists()) {
13698+
return preferred;
13699+
}
13700+
File best = null;
13701+
for (File f : bundles) {
13702+
String name = f.getName();
13703+
if (!name.endsWith(".properties")) {
13704+
continue;
13705+
}
13706+
String base = name.substring(0, name.length() - ".properties".length());
13707+
if (base.indexOf('_') < 0) {
13708+
if (best == null) {
13709+
best = f;
13710+
}
13711+
if ("Bundle".equals(base)) {
13712+
best = f;
13713+
break;
13714+
}
13715+
}
13716+
}
13717+
if (best != null) {
13718+
return best;
13719+
}
13720+
if (!bundles.isEmpty()) {
13721+
java.util.Collections.sort(bundles);
13722+
return bundles.get(0);
13723+
}
13724+
return preferred;
13725+
}
13726+
13727+
private void collectLocalizationBundles(File dir, java.util.List<File> out) {
13728+
File[] files = dir.listFiles();
13729+
if (files == null) {
13730+
return;
13731+
}
13732+
for (File f : files) {
13733+
if (f.isDirectory()) {
13734+
collectLocalizationBundles(f, out);
13735+
} else if (f.getName().endsWith(".properties")) {
13736+
out.add(f);
13737+
}
13738+
}
13739+
}
13740+
13741+
private File findLocalizationDirectory() {
13742+
File projectDir = getCWD();
13743+
File[] candidates = new File[]{
13744+
new File(projectDir, "src" + File.separator + "main" + File.separator + "l10n"),
13745+
new File(projectDir, "l10n"),
13746+
new File(projectDir, "src" + File.separator + "l10n")
13747+
};
13748+
for (File dir : candidates) {
13749+
if (dir.exists() && dir.isDirectory()) {
13750+
return dir;
13751+
}
13752+
}
13753+
File fallback = candidates[0];
13754+
if (!fallback.exists()) {
13755+
fallback.mkdirs();
13756+
}
13757+
if (fallback.exists() && fallback.isDirectory()) {
13758+
return fallback;
13759+
}
13760+
return null;
13761+
}
13762+
13763+
private static class AutoLocalizationBundle extends Hashtable<String, String> {
13764+
private static final long serialVersionUID = 1L;
13765+
13766+
private File bundleFile;
13767+
private final java.util.Properties properties = new java.util.Properties();
13768+
private boolean dirty;
13769+
13770+
AutoLocalizationBundle(File bundleFile, Map<String, String> base) {
13771+
this.bundleFile = bundleFile;
13772+
ensureParentExists();
13773+
if (bundleFile.exists()) {
13774+
loadFromFile();
13775+
} else {
13776+
persist();
13777+
}
13778+
if (base != null && !base.isEmpty()) {
13779+
for (Map.Entry<String, String> entry : base.entrySet()) {
13780+
if (entry.getKey() == null || entry.getValue() == null) {
13781+
continue;
13782+
}
13783+
putInternal(entry.getKey(), entry.getValue());
13784+
storeEntry(entry.getKey(), entry.getValue(), false);
13785+
}
13786+
persistIfNeeded(true);
13787+
}
13788+
}
13789+
13790+
private void loadFromFile() {
13791+
try (InputStream in = new FileInputStream(bundleFile)) {
13792+
properties.clear();
13793+
properties.load(in);
13794+
super.clear();
13795+
for (String name : properties.stringPropertyNames()) {
13796+
putInternal(name, properties.getProperty(name));
13797+
}
13798+
dirty = false;
13799+
} catch (IOException err) {
13800+
Log.e(err);
13801+
}
13802+
}
13803+
13804+
private void ensureParentExists() {
13805+
File parent = bundleFile.getParentFile();
13806+
if (parent != null && !parent.exists()) {
13807+
parent.mkdirs();
13808+
}
13809+
}
13810+
13811+
private void persist() {
13812+
ensureParentExists();
13813+
try (OutputStream out = new FileOutputStream(bundleFile)) {
13814+
properties.store(out, "Codename One auto-generated bundle");
13815+
} catch (IOException err) {
13816+
Log.e(err);
13817+
}
13818+
dirty = false;
13819+
}
13820+
13821+
private void persistIfNeeded(boolean force) {
13822+
if (force) {
13823+
if (dirty || !bundleFile.exists()) {
13824+
persist();
13825+
} else {
13826+
ensureParentExists();
13827+
}
13828+
} else if (dirty) {
13829+
persist();
13830+
}
13831+
}
13832+
13833+
private void storeEntry(String key, String value, boolean flush) {
13834+
if (key == null || value == null) {
13835+
return;
13836+
}
13837+
String current = properties.getProperty(key);
13838+
if (current == null || !current.equals(value)) {
13839+
properties.setProperty(key, value);
13840+
dirty = true;
13841+
}
13842+
if (flush) {
13843+
persistIfNeeded(true);
13844+
}
13845+
}
13846+
13847+
private String putInternal(String key, String value) {
13848+
return (String) super.put(key, value);
13849+
}
13850+
13851+
@Override
13852+
public synchronized String get(Object key) {
13853+
String value = super.get(key);
13854+
if (key instanceof String) {
13855+
String strKey = (String) key;
13856+
if (value == null) {
13857+
String autoValue = strKey;
13858+
putInternal(strKey, autoValue);
13859+
storeEntry(strKey, autoValue, true);
13860+
value = autoValue;
13861+
}
13862+
}
13863+
return value;
13864+
}
13865+
13866+
@Override
13867+
public synchronized String put(String key, String value) {
13868+
String result = putInternal(key, value);
13869+
storeEntry(key, value, true);
13870+
return result;
13871+
}
13872+
13873+
@Override
13874+
public synchronized String remove(Object key) {
13875+
String result = super.remove(key);
13876+
if (key instanceof String) {
13877+
if (properties.containsKey(key)) {
13878+
properties.remove(key);
13879+
dirty = true;
13880+
persistIfNeeded(true);
13881+
} else {
13882+
ensureParentExists();
13883+
}
13884+
}
13885+
return result;
13886+
}
13887+
13888+
@Override
13889+
public synchronized void clear() {
13890+
super.clear();
13891+
if (!properties.isEmpty()) {
13892+
properties.clear();
13893+
dirty = true;
13894+
persistIfNeeded(true);
13895+
} else {
13896+
ensureParentExists();
13897+
}
13898+
}
13899+
13900+
boolean isForFile(File file) {
13901+
return bundleFile.equals(file);
13902+
}
13903+
13904+
void ensureFileExists() {
13905+
ensureParentExists();
13906+
if (!bundleFile.exists()) {
13907+
persist();
13908+
}
13909+
}
13910+
}
13911+
13912+
1362713913
public static File getCWD() {
1362813914
return new File(System.getProperty("user.dir"));
1362913915
}

0 commit comments

Comments
 (0)