1/* 2 ***************************************************************************** 3 * Copyright (C) 2000-2007, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ***************************************************************************** 6 */ 7package com.ibm.rbm; 8 9import java.util.*; 10import java.io.*; 11import javax.swing.UIManager; 12import javax.swing.JOptionPane; 13 14import com.ibm.rbm.gui.RBManagerGUI; 15 16/** 17 * A utility class to aid in the process of updating the Natural Language Support of Tempus Fugit. 18 * This class scans the directory containing NLS files and checks the various languages found there 19 * for completeness, duplication of entry, and status of translation. The class can be instantiated 20 * through a constructor, or it can be run from the command line. For additional information on the 21 * command line results, see the <CODE>main</CODE> method. 22 * 23 * @author Jared Jackson 24 * @see com.ibm.rbm.RBManager 25 */ 26public class RBManager { 27 28 // *** DATA *** 29 private Vector allBundleKeys; // A Vector of Strings with all defined NLS properties 30 private Vector bundles; // A Vector of NLSbundles, one for each language 31 private String currentUser; // The name of the person currently using the editor 32 private String baseClass; // The name of the base class of the active resource bundle 33 private File currentDirectory; 34 35 // *** CONSTRUCTORS *** 36 37 // The default constructor is not publicly available 38 private RBManager() { 39 try { 40 // Look and Feel check 41 try { 42 String laf = Preferences.getPreference("lookandfeel"); 43 if (!laf.equals("")) UIManager.setLookAndFeel(laf); 44 } catch (Exception e) { 45 // Ignored 46 } 47 48 Resources.initBundle(); 49 RBManagerGUI guiFrame = new RBManagerGUI(); 50 if (!Preferences.getPreference("username").equals("")) 51 guiFrame.setUser(Preferences.getPreference("username")); 52 if (!Preferences.getPreference("locale").equals("")) { 53 String localeStr = Preferences.getPreference("locale"); 54 String language = Resources.getLanguage(localeStr); 55 String country = Resources.getCountry(localeStr); 56 String variant = Resources.getVariant(localeStr); 57 if (language == null || language.equals("") || language.length() > 3) language = "en"; 58 if (country == null) country = new String(); 59 if (variant == null) Resources.setLocale(new Locale(language, country)); 60 else Resources.setLocale(new Locale(language, country, variant)); 61 } 62 Resources.initBundle(); 63 guiFrame.initComponents(); 64 guiFrame.setVisible(true); 65 } catch (Exception e) { 66 e.printStackTrace(); 67 } 68 } 69 70 /** 71 * This constructor creates an entirely blank RBManager and base Bundle. Only the base class name is defined. 72 * All other properties need to be defined. 73 */ 74 75 public RBManager(String baseClassName) { 76 allBundleKeys = new Vector(); 77 bundles = new Vector(); 78 currentUser = "Unknown"; 79 baseClass = baseClassName; 80 currentDirectory = new File(""); 81 82 Bundle mainBundle = new Bundle(""); 83 // Create a default group 84 mainBundle.addBundleGroup("Ungrouped Items", "These are resource items that have not been assigned a group"); 85 bundles.addElement(mainBundle); 86 } 87 88 /** 89 * This is the standard constructor for RBManager. It is constructed from the root of a resource bundle. 90 * In the current implementation, each file is parsed separately starting with the base class file (root). 91 * In this implementation, the lookup keys are represented to the user as they appear in the files. The 92 * translation values however are translated according to the basic rules defined in java.util.Properties. 93 * Thus in the key, the user may see '\"' when in the value it would have been converted to '"'. This 94 * translation is reversed when saving the resource bundle. 95 * @param mainFile The base class file of the resource bundle to be read 96 */ 97 98 public RBManager(File mainFile) throws FileNotFoundException, IOException { 99 init(); 100 101 currentDirectory = new File(mainFile.getParent()); 102 103 String[] encodings; 104 105 // Initialize the readers to the main NLS file 106 FileReader fr = new FileReader(mainFile); 107 BufferedReader br = new BufferedReader(fr); 108 109 // Load the java readable values from the main NLS file; 110 Properties p = new Properties(); 111 p.load(new FileInputStream(mainFile)); 112 113 // Count the number of language files and set up the encoding and dictionary data 114 int numLanguages = 1; 115 String NLSbaseClass = null; 116 String NLSpostfix = null; 117 118 if (mainFile.getName().indexOf(".") >= 0) { 119 NLSbaseClass = mainFile.getName().substring(0,mainFile.getName().indexOf(".")); 120 NLSpostfix = ".properties"; 121 } else { 122 NLSbaseClass = mainFile.getName(); 123 NLSpostfix = ""; 124 } 125 126 baseClass = NLSbaseClass; 127 128 String filePrefix = mainFile.getName().substring(0,mainFile.getName().lastIndexOf(".")); 129 String filePostfix = mainFile.getName().substring(mainFile.getName().lastIndexOf("."),mainFile.getName().length()); 130 File resDir = currentDirectory; 131 if (resDir != null && resDir.isDirectory()) { 132 String[] temp = resDir.list(); 133 numLanguages = 0; 134 // Count the number of language files 135 for (int i = 0; i < temp.length; i++) { 136 if (temp[i].startsWith(NLSbaseClass) && (temp[i].endsWith(NLSpostfix) 137 || temp[i].endsWith(NLSpostfix.toUpperCase()) || NLSpostfix.equals(""))) { 138 // Starts with the base class name and ends in proper suffix (above) 139 // Base name is followed by . or _ (below) 140 RBManagerGUI.debugMsg("Character is: " + temp[i].charAt(NLSbaseClass.length())); 141 if (temp[i].charAt(NLSbaseClass.length()) == '.' || temp[i].charAt(NLSbaseClass.length()) == '_') 142 numLanguages++; 143 } 144 } 145 // Initialize the bundles and encodings 146 encodings = new String[numLanguages]; 147 148 int count = 1; 149 for (int i = 0; i < temp.length; i++) { 150 if (temp[i].equals(mainFile.getName())) { 151 encodings[0] = ""; 152 } else if (temp[i].startsWith(NLSbaseClass) && (temp[i].endsWith(NLSpostfix) 153 || temp[i].endsWith(NLSpostfix.toUpperCase()) || NLSpostfix.equals(""))) { 154 if (temp[i].charAt(NLSbaseClass.length()) == '.' || temp[i].charAt(NLSbaseClass.length()) == '_') { 155 encodings[count] = new String(temp[i].substring(filePrefix.length()+1,temp[i].indexOf(filePostfix))); count++; 156 } 157 } 158 } 159 } else { 160 // Initialize the bundles and encodings in case the directory information is not available 161 // In this case, only the main NLS file will be handled 162 encodings = new String[numLanguages]; 163 encodings[0] = new String(""); 164 } // end the count and initialization 165 166 // Read in the entries from the main file 167 String line; 168 // Set the dictionary for the main file 169 Bundle dict = new Bundle(encodings[0]); 170 bundles.addElement(dict); 171 // Set up the first group in case there are NLS items which were not assigned to a group 172 BundleGroup group = new BundleGroup(dict, "Ungrouped Items"); 173 group.setComment("NLS Items which were not initially assigned to a group"); 174 dict.addBundleGroup(group); 175 BundleItem item = new BundleItem(group,null,null); 176 int count = 0; 177 while ((line = br.readLine()) != null) { 178 // Test to make sure this is a file that was generated by RBManager 179 if (!line.trim().equals("")) count++; 180 if (count == 1 && !line.startsWith("# @file")) { 181 // Not generated by RBManager 182 JOptionPane.showMessageDialog(null, 183 Resources.getTranslation("error_not_rbmanager_format") + "\n" + Resources.getTranslation("error_suggest_import_properties"), 184 Resources.getTranslation("dialog_title_error_not_rbmanager_format"), JOptionPane.ERROR_MESSAGE); 185 throw new FileNotFoundException("Improper format for file: " + mainFile.getName()); 186 } 187 String commentLine = null; 188 // Grab text following the # sign 189 if (line.indexOf("#") >= 0) { 190 commentLine = line.substring(line.indexOf("#")+1,line.length()); 191 line = line.substring(0,line.indexOf("#")); 192 } 193 if (commentLine != null && commentLine.trim().length() > 0) { 194 // Process any information made available in comment '@' information 195 Hashtable descriptors = getDescriptors(null,commentLine); 196 if (descriptors != null) { 197 Object o; 198 // File tags 199 o = descriptors.get("file"); if (o != null) dict.name = ((String) o); 200 o = descriptors.get("fileComment"); if (o != null) dict.comment = ((String) o); 201 o = descriptors.get("fileLanguage"); if (o != null) dict.language = ((String) o); 202 o = descriptors.get("fileCountry"); if (o != null) dict.country = ((String) o); 203 o = descriptors.get("fileVariant"); if (o != null) dict.variant = ((String) o); 204 o = descriptors.get("fileManager"); if (o != null) dict.manager = ((String) o); 205 206 // Group tags 207 o = descriptors.get("group"); 208 if (o != null) { 209 group = new BundleGroup(dict, (String)o); 210 item.setParentGroup(group); 211 dict.addBundleGroup(group); 212 } 213 o = descriptors.get("groupComment"); if (o != null) group.setComment((String) o); 214 215 // Item tags 216 o = descriptors.get("comment"); if (o != null) item.setComment((String) o); 217 o = descriptors.get("translated"); if (o != null) item.setTranslated(((String) o).equalsIgnoreCase("true")); 218 o = descriptors.get("creator"); if (o != null) item.setCreator((String) o); 219 o = descriptors.get("modifier"); if (o != null) item.setModifier((String) o); 220 o = descriptors.get("created"); if (o != null) item.setCreatedDate((String) o); 221 o = descriptors.get("modified"); if (o != null) item.setModifiedDate((String) o); 222 223 // Lookup tags (e.g. {_#_} _description_) 224 Enumeration keys = descriptors.keys(); 225 while (keys.hasMoreElements()) { 226 String tag = (String)keys.nextElement(); 227 if (tag.startsWith("{")) { 228 if (tag.indexOf("}") < 0) continue; 229 String lookup = tag.substring(1,tag.indexOf("}")); 230 item.getLookups().put(lookup, descriptors.get(tag)); 231 } 232 } 233 } 234 } // end check of comment line 235 if (line.trim().length() < 1) continue; 236 237 // Grab the name and value (translation) from the line 238 int breakpoint = 0; 239 boolean started = false; 240 char array[] = line.toCharArray(); 241 for (int i=0; i < array.length; i++) { 242 if (!started && array[i] != ' ' && array[i] != '\t') started = true; 243 if (started && (array[i] == '=' || array[i] == ':' || array[i] == ' ' || array[i] == '\t')) { 244 breakpoint = i; 245 break; 246 } 247 } 248 String key = String.valueOf(array,0,breakpoint); 249 250 item.setKey(key); 251 String translation = p.getProperty(key); 252 if (translation == null || translation.equals("")) 253 item.setTranslation(line.substring(line.indexOf("=")+1,line.length()).trim()); 254 else item.setTranslation(translation); 255 256 dict.addBundleItem(item); 257 item = new BundleItem(group,null,null); 258 } // end while - main NLS file 259 260 // Now that we have parsed the entire main language file, populate the allNLSKey set with the dictionary keys 261 allBundleKeys = new Vector(); 262 Enumeration keys = ((Bundle)bundles.elementAt(0)).allItems.keys(); 263 while (keys.hasMoreElements()) { 264 allBundleKeys.addElement(keys.nextElement()); 265 } 266 267 // Now go through all of the other languages 268 for (int i = 1; i < encodings.length; i++) { 269 if (encodings[i].equals("kr")) continue; // I can't handle double byte character sets yet 270 // Try to obtain the new file 271 File tempFile = new File(resDir, NLSbaseClass + "_" + encodings[i] + NLSpostfix); 272 fr = new FileReader(tempFile); 273 br = new BufferedReader(fr); 274 275 // Try to obtain the java readable properties for the file 276 p = new Properties(); 277 p.load(new FileInputStream(tempFile)); 278 279 // Set the dictionary for the main file 280 dict = new Bundle(encodings[i]); 281 bundles.addElement(dict); 282 // Set up the first group in case there are NLS items which were not assigned to a group 283 group = new BundleGroup(dict, "Ungrouped Items"); 284 dict.addBundleGroup(group); 285 group.setComment("NLS Items which were not initially assigned to a group"); 286 item = new BundleItem(group,null,null); 287 // Create the rest of the groups 288 while ((line = br.readLine()) != null) { 289 String commentLine = null; 290 // Grab the text following the # sign 291 if (line.indexOf("#") >= 0) { 292 commentLine = line.substring(line.indexOf("#")+1,line.length()); 293 line = line.substring(0,line.indexOf("#")); 294 } 295 if (commentLine != null && commentLine.trim().length() > 0) { 296 // Process any information made available in comment '@' information 297 Hashtable descriptors = getDescriptors(null,commentLine); 298 if (descriptors != null) { 299 Object o; 300 // File tags 301 o = descriptors.get("file"); if (o != null) dict.name = ((String) o); 302 o = descriptors.get("fileComment"); if (o != null) dict.comment = ((String) o); 303 o = descriptors.get("fileLanguage"); if (o != null) dict.language = ((String) o); 304 o = descriptors.get("fileCountry"); if (o != null) dict.country = ((String) o); 305 o = descriptors.get("fileVariant"); if (o != null) dict.variant = ((String) o); 306 o = descriptors.get("fileManager"); if (o != null) dict.manager = ((String) o); 307 308 // Group tags 309 o = descriptors.get("group"); 310 if (o != null) { 311 group = new BundleGroup(dict, (String)o); 312 item.setParentGroup(group); 313 dict.addBundleGroup(group); 314 } 315 o = descriptors.get("groupComment"); if (o != null) group.setComment((String) o); 316 317 // Item tags 318 o = descriptors.get("comment"); if (o != null) item.setComment((String) o); 319 o = descriptors.get("translated"); if (o != null) item.setTranslated(((String) o).equalsIgnoreCase("true")); 320 o = descriptors.get("creator"); if (o != null) item.setCreator((String) o); 321 o = descriptors.get("modifier"); if (o != null) item.setModifier((String) o); 322 o = descriptors.get("created"); if (o != null) item.setCreatedDate((String) o); 323 o = descriptors.get("modified"); if (o != null) item.setModifiedDate((String) o); 324 325 // Lookup tags (e.g. {_#_} _description_) 326 Enumeration descKeys = descriptors.keys(); 327 while (descKeys.hasMoreElements()) { 328 String tag = (String)descKeys.nextElement(); 329 if (tag.startsWith("{")) { 330 if (tag.indexOf("}") < 0) continue; 331 String lookup = tag.substring(1,tag.indexOf("}")); 332 item.getLookups().put(lookup, descriptors.get(tag)); 333 } 334 } 335 } 336 } // end check of comment line 337 if (line.trim().length() < 1) continue; 338 339 // Grab the name and value (translation) from the line 340 int breakpoint = 0; 341 boolean started = false; 342 char array[] = line.toCharArray(); 343 for (int j=0; j < array.length; j++) { 344 if (!started && array[j] != ' ' && array[j] != '\t') started = true; 345 if (started && (array[j] == '=' || array[j] == ':' || array[j] == ' ' || array[j] == '\t')) { 346 breakpoint = j; 347 break; 348 } 349 } 350 String key = String.valueOf(array,0,breakpoint); 351 item.setKey(key); 352 String translation = p.getProperty(key); 353 if (translation == null || translation.equals("")) 354 item.setTranslation(line.substring(line.indexOf("=")+1,line.length()).trim()); 355 else item.setTranslation(translation); 356 357 dict.addBundleItem(item); 358 item = new BundleItem(group,null,null); 359 } // end while - next line 360 } // end for looop through languages 361 // Add this opened file to our recent files 362 Preferences.addRecentFilePreference(mainFile.getName(), mainFile.getAbsolutePath()); 363 } // end RBManager() 364 365 // *** METHODS *** 366 367 /** 368 * Main 369 */ 370 371 public static void main(String args[]) { 372 // Make sure the user specified a path 373 if (args.length < 1) { 374 new RBManager(); 375 return; 376 } 377 } // main 378 379 public String toString() { return baseClass; } 380 381 /** 382 * Write the contents of the file to the output stream 383 */ 384 385 public void writeToFile() throws IOException { 386 for (int i = 0; i < bundles.size(); i++) { 387 Bundle bundle = (Bundle)bundles.elementAt(i); 388 File outputFile = new File(currentDirectory, baseClass + 389 ((bundle.encoding == null || bundle.encoding.equals("")) ? "" : "_" + bundle.encoding) + 390 ".properties"); 391 FileWriter fw = new FileWriter(outputFile); 392 bundle.writeContents(fw); 393 fw.flush(); 394 fw.close(); 395 } 396 // In case this is a newly created bundle or the location has changed recently, update the recent files, preference 397 Preferences.addRecentFilePreference(baseClass + ".properties", currentDirectory.getAbsolutePath() + File.separator + 398 baseClass + ".properties"); 399 } 400 401 /** 402 * Calling this method removes a resource from the resource bundle. This method does not permanently 403 * erase the file containing the resources at this encoding, however any changes or saves that take 404 * place once this file has been removed will not be reflected in this hidden file. To restore the resource, 405 * the bundle will have to be recreated. (This last point may change) 406 */ 407 408 public void hideResource(String encoding) { 409 for (int i=0; i < bundles.size(); i++) { 410 Bundle bundle = (Bundle)bundles.elementAt(i); 411 if (bundle.encoding.equals(encoding)) { 412 bundles.removeElement(bundle); 413 break; 414 } 415 } 416 } 417 418 /** 419 * Erases permanently one of the resource files. Be careful about calling this method there is nothing you can do 420 * once a file is erased. 421 */ 422 423 public void eraseFile(String encoding) throws IOException { 424 for (int i = 0; i < bundles.size(); i++) { 425 Bundle bundle = (Bundle)bundles.elementAt(i); 426 if (!(bundle.encoding.equals(encoding))) continue; 427 File outputFile = new File(currentDirectory, baseClass + 428 ((bundle.encoding == null || bundle.encoding.equals("")) ? "" : "_" + bundle.encoding) + 429 ".properties"); 430 boolean success = outputFile.delete(); 431 if (!success) throw new IOException(Resources.getTranslation("error_deletion_not_possible")); 432 hideResource(encoding); 433 break; 434 } 435 } 436 437 /** 438 * Writes only one of the resource files to the file system. This file is specified by the encoding parameter 439 */ 440 441 public void writeToFile(String encoding) throws IOException { 442 for (int i = 0; i < bundles.size(); i++) { 443 Bundle bundle = (Bundle)bundles.elementAt(i); 444 if (bundle.encoding.equals(encoding) || (i==0 && encoding.equals(""))) { 445 File outputFile = new File(currentDirectory, baseClass + 446 ((bundle.encoding == null || bundle.encoding.equals("")) ? "" : "_" + bundle.encoding) + 447 ".properties"); 448 FileWriter fw = new FileWriter(outputFile); 449 bundle.writeContents(fw); 450 fw.flush(); 451 fw.close(); 452 break; 453 } 454 } 455 // In case this is a newly created bundle or the location has changed recently, update the recent files, preference 456 Preferences.addRecentFilePreference(baseClass + ".properties", currentDirectory.getAbsolutePath() + File.separator + 457 baseClass + ".properties"); 458 } 459 460 /** 461 * Given a BundleItem and some properties to change for that item, this method first checks to make sure the passed 462 * item is valid and if it is, the properties of that item are changed to reflect those passed in as parameters to this 463 * method. 464 * @return true if the BundleItem was valid and updateable, false if otherwise (in this case no changes were made). 465 */ 466 467 public boolean editItem(BundleItem item, String name, String value, String groupName, String comment, Hashtable lookups) { 468 if (name == null || name.equals("") || groupName == null || groupName.equals("") || item == null) return false; 469 String oldName = item.getKey(); 470 String oldComment = item.getComment(); 471 String oldValue = item.getTranslation(); 472 //String oldGroupName = item.getParentGroup().getName(); 473 // Loop through the bundles 474 for (int i = 0; i < bundles.size(); i++) { 475 Bundle bundle = (Bundle)bundles.elementAt(i); 476 BundleItem oldItem = (BundleItem)bundle.allItems.get(oldName); 477 if (oldItem == null) break; 478 if (!oldName.equals(name)) { 479 // A new key 480 oldItem.setKey(name); 481 bundle.allItems.remove(oldItem); 482 bundle.allItems.put(oldItem.getKey(), oldItem); 483 } 484 if (oldItem.getComment() == null || oldItem.getComment().equals(oldComment)) oldItem.setComment(comment); 485 if (oldItem.getTranslation().equals(oldValue)) oldItem.setTranslation(value); 486 oldItem.setLookups(lookups); 487 if (!oldItem.getParentGroup().getName().equals(groupName)) { 488 // A new group 489 oldItem.getParentGroup().removeBundleItem(oldItem.getKey()); 490 BundleGroup bg = bundle.getBundleGroup(groupName); 491 if (bg == null) bg = bundle.getUngroupedGroup(); 492 oldItem.setParentGroup(bg); 493 bg.addBundleItem(oldItem); 494 } 495 } 496 return true; 497 } 498 499 /** 500 * Attempts to create a new item in each of the language files. The method first checks the base Resource Bundle 501 * to make sure that the item name does not all ready exist. If it does exist the item is not created. 502 * @param name The unique key of the item 503 * @param value The translation of the item for the base class 504 * @param groupName The group name, should all ready exist in the base class 505 * @param comment An optional comment to be added to the item, can be <CODE>null</CODE> 506 * @return An error response. If the creation was successful <CODE>true</CODE> is returned, if there was an error <CODE>false</CODE> is returned. 507 */ 508 509 public boolean createItem(String name, String value, String groupName, String comment, Hashtable lookups) { 510 if (name == null || name.equals("") || groupName == null || groupName.equals("")) return false; 511 Bundle mainBundle = (Bundle)bundles.firstElement(); 512 BundleGroup mainGroup = null; 513 if (mainBundle.allItems.containsKey(name)) return false; 514 for (int i=0; i < mainBundle.getGroupCount(); i++) { 515 BundleGroup bg = mainBundle.getBundleGroup(i); 516 if (bg.getName().equals(groupName)) {mainGroup = bg; break;} 517 } 518 if (mainGroup == null) return false; 519 // Add to the base class 520 BundleItem mainItem = new BundleItem(mainGroup, name, value); 521 mainItem.setTranslated(true); 522 mainItem.setCreator(currentUser); 523 mainItem.setModifier(currentUser); 524 mainItem.setComment(comment); 525 mainBundle.allItems.put(name, mainItem); 526 mainGroup.addBundleItem(mainItem); 527 if (lookups != null) mainItem.setLookups(lookups); 528 // Add to the rest of the bundles 529 for (int i=1; i < bundles.size(); i++) { 530 Bundle bundle = (Bundle)bundles.elementAt(i); 531 // Find the group 532 BundleGroup group = null; 533 for (int j=0; j < bundle.getGroupCount(); j++) { 534 BundleGroup bg = bundle.getBundleGroup(j); 535 if (bg.getName().equals(groupName)) {group = bg; break;} 536 } 537 if (group == null) { 538 group = new BundleGroup(bundle, groupName); 539 bundle.addBundleGroup(group); 540 } 541 BundleItem item = new BundleItem(group, name, value); 542 item.setCreator(currentUser); 543 item.setModifier(currentUser); 544 item.setComment(comment); 545 if (lookups != null) item.setLookups(lookups); 546 bundle.allItems.put(name, item); 547 bundle.addUntranslatedItem(item); 548 group.addBundleItem(item); 549 } 550 return true; 551 } 552 553 /** 554 * Attempts to create a new group in each of the language files. The method first checks the base Resource Bundle 555 * to make sure that the group name does not all ready exist. If it does exist the group is not created. 556 * @param groupName The unique group name to be created 557 * @param groupComment An optional comment to be added to the group, can be <CODE>null</CODE> 558 * @return An error response. If the creation was successful <CODE>true</CODE> is returned, if there was an error <CODE>false</CODE> is returned. 559 */ 560 public boolean createGroup(String groupName, String groupComment) { 561 if (groupName == null || groupName.equals("")) 562 return false; 563 // Check to see if the group exists 564 Bundle mainBundle = (Bundle)bundles.firstElement(); 565 if (mainBundle.hasGroup(groupName)) 566 return false; 567 568 // Create the group 569 for (int i=0; i < bundles.size(); i++) { 570 Bundle bundle = (Bundle)bundles.elementAt(i); 571 BundleGroup bg = new BundleGroup(bundle, groupName); 572 if (groupComment != null) 573 bg.setComment(groupComment); 574 bundle.addBundleGroup(bg); 575 } 576 return true; 577 } 578 579 /** 580 * Removes a group and all of the items within that group from the various 581 * Resource Bundles known to the system. This method removes the group from 582 * the protected vector of groups, then removes all items in that group from 583 * the protected vector of untranslated items, and the protected hashtable of 584 * all items. 585 */ 586 587 public void deleteGroup(String groupName) { 588 if (groupName == null) return; 589 // Loop through all of the bundles; 590 for (int i=0; i < bundles.size(); i++) { 591 Bundle bundle = (Bundle)bundles.elementAt(i); 592 bundle.removeGroup(groupName); 593 } 594 } 595 596 /** 597 * Remove resource items of the given name from each of the resource bundles that the system 598 * knows about. This works by first removing the item from the protected vector of translated 599 * items, if it is there, and then removing it from the the hashtable of all items, and then 600 * removing it from its respective group. 601 */ 602 603 public void deleteItem(String itemName) { 604 if (itemName == null) return; 605 // Loop through all of the bundles; 606 for (int i=0; i < bundles.size(); i++) { 607 // Loop through untranslated items 608 Bundle bundle = (Bundle)bundles.elementAt(i); 609 bundle.removeUntranslatedItem(itemName); 610 611 // Loop through all Items 612 Enumeration items = bundle.allItems.elements(); 613 while(items.hasMoreElements()) { 614 BundleItem item = (BundleItem)items.nextElement(); 615 if (item.getKey().equals(itemName)) { 616 bundle.allItems.remove(item); 617 item.getParentGroup().removeBundleItem(item.getKey()); 618 } 619 } 620 } 621 } 622 623 /** 624 * Looks through the resources contained in the bundle for a resource of the given encoding. Note that this 625 * search is case sensitive. 626 * @return True if the encoding exists as one of the resource files, false otherwise 627 */ 628 629 public boolean hasResource(String encoding) { 630 // Check to see if the encoding exists 631 for (int i=0; i < bundles.size(); i++) { 632 Bundle b = (Bundle)bundles.elementAt(i); 633 if (b.encoding.equals(encoding)) return true; 634 } 635 return false; 636 } 637 638 /** 639 * Attempts to create a new resource file with the given encoding. The method first checks the base Resource Bundle 640 * to make sure that encoding does not all ready exist. If it does exist the resource file is not created. 641 * @param title An optional, quick title for the file, can be <CODE>null</CODE> 642 * @param comment An optional comment to be added to the resource, can be <CODE>null</CODE> 643 * @param manager The name of the person responsible for this resource, can be <CODE>null</CODE> 644 * @param encoding The proper encoding for the resource. Must be of form 'language', 'language_country', or 'language_country_variant' 645 * @param language A more formal name for the language (e.g. 'English', 'Deutsch', etc.), can be <CODE>null</CODE> 646 * @param country A more formal name for the country described by the resource, can be <CODE>null</CODE> 647 * @param variant A more formal name for the variant described by the resource, can be <CODE>null</CODE> 648 * @param copyValues An indication of wether or not to populate the resource with the items in the base class 649 * @return An error response. If the creation was successful <CODE>true</CODE> is returned, if there was an error <CODE>false</CODE> is returned. 650 */ 651 652 public boolean createResource(String title, String comment, String manager, String encoding, 653 String language, String country, String variant, boolean copyValues) { 654 if (encoding == null || encoding.equals("") || encoding.startsWith("_")) return false; 655 // Check to see if the encoding exists 656 if (hasResource(encoding)) return false; 657 // Create the resource 658 Bundle bundle = new Bundle(encoding); 659 bundle.name = title; 660 bundle.comment = comment; 661 bundle.manager = manager; 662 bundle.language = language; 663 bundle.country = country; 664 bundle.variant = variant; 665 666 // Create a default group 667 bundle.addBundleGroup("Ungrouped Items", "These are resource items that have not been assigned a group"); 668 669 if (copyValues) { 670 Bundle mainBundle = (Bundle)bundles.firstElement(); 671 for (int i=0; i < mainBundle.getGroupCount(); i++) { 672 BundleGroup mainGroup = mainBundle.getBundleGroup(i); 673 BundleGroup bg = new BundleGroup(bundle,mainGroup.getName()); 674 bg.setComment(mainGroup.getComment()); 675 bundle.addBundleGroup(bg); 676 for (int j=0; j < mainGroup.getItemCount(); j++) { 677 BundleItem mainItem = mainGroup.getBundleItem(j); 678 BundleItem item = new BundleItem(bg, mainItem.getKey(), mainItem.getTranslation()); 679 item.setComment(mainItem.getComment()); 680 item.setCreator(mainItem.getCreator()); 681 item.setModifier(mainItem.getModifier()); 682 item.setLookups(new Hashtable()); 683 // TODO: This should be done in the Bundle class 684 Enumeration keys = mainItem.getLookups().keys(); 685 while (keys.hasMoreElements()) { 686 String name = (String)keys.nextElement(); 687 String value = (String)mainItem.getLookups().get(name); 688 item.getLookups().put(new String(name), new String(value)); 689 } 690 bg.addBundleItem(item); 691 bundle.addUntranslatedItem(item); 692 } 693 } 694 } 695 696 bundles.addElement(bundle); 697 698 return true; 699 } 700 701 /** 702 * Returns the number of duplicate NLS entries 703 */ 704 705 public int getNumberDuplicates() { 706 return ((Bundle)bundles.firstElement()).duplicates.size(); 707 } 708 709 /** 710 * Returns a single string with a comma delimited listing of all duplicate entries found in the NLS resources 711 */ 712 713 public String getDuplicatesListing() { 714 return listStrings(getDuplicatesListingVector()); 715 } 716 717 /** 718 * Returns a Vector collection of duplicate BundleItems found in the bundle 719 */ 720 721 public Vector getDuplicatesListingVector() { 722 return ((Bundle)bundles.firstElement()).duplicates; 723 } 724 725 /** 726 * A useful debugging method that lists the various BundleGroup names in a String. 727 */ 728 729 public String getGroupListing() { 730 return listStrings(getGroupListingVector()); 731 } 732 733 /** 734 * Returns a vector collection of all of the BundleGroup items founds int the bundle. 735 */ 736 737 public Vector getGroupListingVector() { 738 Vector v = new Vector(); 739 Bundle bundle = (Bundle)bundles.firstElement(); 740 for (int i=0; i < bundle.getGroupCount(); i++) { 741 String name = bundle.getBundleGroup(i).getName(); 742 v.addElement(name); 743 } 744 return v; 745 } 746 747 /** 748 * Returns the total number of languages that the system seems to support 749 */ 750 751 public int getNumberLanguages() { 752 return bundles.size(); 753 } 754 755 /** 756 * Returns a single string comprised of a comma delimited listing of all languages the system seems to support 757 */ 758 759 public String getLanguageListing() { 760 return listStrings(getLanguageListingVector()); 761 } 762 763 /** 764 * Returns a vector of strings comprising a list of all languages in the system 765 */ 766 767 public Vector getLanguageListingVector() { 768 Vector v = new Vector(); 769 770 for (int i = 0; i < bundles.size(); i++) { 771 Bundle dict = (Bundle)bundles.elementAt(i); 772 String dictStr = new String(); 773 if (dict.language != null) dictStr += dict.language; 774 if (dict.country != null) dictStr += " " + dict.country; 775 if (dict.variant != null) dictStr += " " + dict.variant; 776 if (dictStr.trim().equals("")) dictStr = (dict.encoding.trim().equals("") ? "Base Resource Bundle" : dict.encoding); 777 v.addElement(dictStr); 778 } 779 780 return v; 781 } 782 783 /** 784 * Returns the number of translations contained across all language files 785 */ 786 787 public int getNumberTotalTranslations() { 788 return allBundleKeys.size(); 789 } 790 791 /** 792 * Returns the number of BundleGroups in the bundle. 793 */ 794 795 public int getNumberGroups() { 796 return ((Bundle)bundles.firstElement()).getGroupCount(); 797 } 798 799 /** 800 * Returns the name of the user currently using the editor 801 */ 802 803 public String getUser() { 804 return currentUser; 805 } 806 807 /** 808 * Sets the name of the user currently using the editor 809 */ 810 811 public void setUser(String user) { 812 currentUser = user; 813 } 814 815 /** 816 * Sets the name of the base class associated with this resource bundle 817 */ 818 819 public void setBaseClass(String baseClassName) { 820 baseClass = baseClassName; 821 } 822 823 /** 824 * Sets the directory in the file system in which this resource bundle is to be 825 * saved and retrieved. 826 */ 827 828 public void setFileDirectory(File directory) { 829 if (directory.isDirectory()) currentDirectory = directory; 830 } 831 832 /** 833 * Returns the base class name if known, or "Unknown Base Class" otherwise. 834 */ 835 public String toSring() { 836 return (baseClass == null ? "Unknown Base Class" : baseClass); 837 } 838 839 /** 840 * Returns the base class name or null if it does not exist. 841 */ 842 843 public String getBaseClass() { 844 return baseClass; 845 } 846 847 /** 848 * A Vector of NLSbundles, one for each language 849 */ 850 public Vector getBundles() { 851 return bundles; 852 } 853 854 /** 855 * Return a bundle from a locale 856 * @return The requested resource bundle 857 */ 858 public Bundle getBundle(String locale) { 859 Bundle bundle = null; 860 if (hasResource(locale)) { 861 for (int i = 0; i < bundles.size(); i++) { 862 Bundle tempb = (Bundle)bundles.elementAt(i); 863 if (tempb.encoding.equals(locale)) { 864 bundle = tempb; 865 break; 866 } 867 } 868 } 869 return bundle; 870 } 871 872 /** 873 * Returns the name of the file that is the base class file for the resource bundle. 874 */ 875 876 public File getBaseFile() { 877 return new File(currentDirectory,baseClass + ".properties"); 878 } 879 880 // Return a single comma delimited string made from a vector of strings 881 private String listStrings(Vector v) { 882 String retStr = new String(); 883 for (int i = 0; i < v.size(); i++) { 884 Object o = v.elementAt(i); 885 if (!(o instanceof String)) continue; 886 String s = (String)o; 887 if (i > 0) retStr += ", "; 888 retStr += s; 889 } 890 return retStr; 891 } 892 893 // Init - called before ant construction 894 private void init() { 895 allBundleKeys = new Vector(); 896 bundles = new Vector(); 897 currentUser = "Unknown"; 898 } 899 900 // Return a hashtable of the tags in a comment line (i.e. the text after each '@' character) and their values 901 private Hashtable getDescriptors(Hashtable result, String line) { 902 // Recursion terminating condition 903 if (line == null || line.length() <= 0 || line.indexOf("@") < 0) return result; 904 // Otherwise generate what information we can and recurse 905 if (result == null) result = new Hashtable(); 906 // Strip off any information before and including a '@' 907 line = line.substring(line.indexOf("@")+1, line.length()); 908 // There should be a space after the '@_tag_' and the value of this property 909 if (line.indexOf(" ") < 0) return result; // This shouldn't happen if things are formatted right 910 // Add the text after the '@' character up to the first whitespace (has to be a space, not tab or other whitespace) 911 String name = line.substring(0,line.indexOf(" ")).trim(); 912 // Now strip off the tag name 913 line = line.substring(line.indexOf(" "), line.length()); 914 // If there is another '@' character we take the value up until that character 915 if (line.indexOf("@") >= 0) { 916 result.put(name,line.substring(0,line.indexOf("@")).trim()); 917 } 918 // Otherwise we take the rest of the characters in the line 919 else { 920 result.put(name,line.trim()); 921 return result; 922 } 923 // Recurse 924 return getDescriptors(result, line.substring(line.indexOf("@"), line.length())); 925 } 926 927 // Checks an array of strings to see if it contains a particular string 928/* private static boolean arrayContains(String[] array, String match) { 929 for (int i = 0; i < array.length; i++) { 930 if (array[i].equals(match)) return true; 931 } 932 return false; 933 }*/ 934 935 // Prints the usage of the program when called from main 936/* private static void printUsage() { 937 String usage = new String(); 938 usage += "Usage:\n\njava com.ibm.almaden.TempusFugit.Tools.RBManager fileName ((-r | -d) encoding?)?"; 939 usage += "\n\n fileName -> The file (and path?) representing the main NLS resource\n\t\t(i.e. TempusFugit.resources)\n"; 940 usage += " encoding -> Returns results for only the language encoding specified\n"; 941 usage += " flag -r -> Gives only a status report on the state of the translations\n"; 942 System.out.println(usage); 943 }*/ 944 945} 946 947