- Timestamp:
- 2003-05-27T15:57:37+12:00 (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java
r4293 r4366 112 112 // #################################################################################### 113 113 public class ClassifierManager 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 114 implements MSMListener { 115 /** An interface to the Gatherer, the creator of this cdm module, for access to the Greenstone installation directory. */ 116 private Gatherer gatherer = null; 117 /** A reference to the CollectionDesignManager for access to other configuration managers. */ 118 private CollectionDesignManager manager = null; 119 /** The controls for editing the contents of this manager. */ 120 private Control controls = null; 121 /** A list of assigned classifiers. */ 122 private DynamicListModel assigned = null; 123 /** A list of known, but currently unassigned, classifiers. */ 124 private DynamicListModel reserve = null; 125 /** We may have somehow recieved a classifier command that are, in fact, custom classifiers which can refer to classifiers that haven't been parsed yet, so this holds a list of failed commands which are retried after the loading is complete. */ 126 private ArrayList unresolved_commands = null; 127 /** Constructor. 128 * @param gatherer A reference to the <strong>Gatherer</strong> for access to the Dictionary. 129 * @param manager A reference to the <strong>CollectionDesignManager</strong> itself. 130 * @see org.greenstone.gatherer.Gatherer 131 * @see org.greenstone.gatherer.cdm.DynamicListModel 132 * @see org.greenstone.gatherer.collection.CollectionManager 133 * @see org.greenstone.gatherer.msm.MetadataSetManager 134 * @see org.greenstone.gatherer.msm.MSMListener 135 */ 136 public ClassifierManager(Gatherer gatherer, CollectionDesignManager manager) { 137 this.assigned = new DynamicListModel(); 138 this.gatherer = gatherer; 139 this.manager = manager; 140 this.unresolved_commands = new ArrayList(); 141 loadClassifiers(); 142 saveClassifiers(); 143 // Register as a MSMListener. 144 Gatherer.c_man.getCollection().msm.addMSMListener(this); 145 } 146 /** Method to add a new classifier to reserve. 147 147 * @param classifier The new <strong>Classifier</strong>. 148 148 * @see org.greenstone.gatherer.cdm.DynamicListModel 149 149 */ 150 151 152 153 154 155 150 public void addClassifier(Classifier classifier) { 151 if(!reserve.contains(classifier)) { 152 reserve.addElement(classifier); 153 } 154 } 155 /** Method to assign a classifier. 156 156 * @param classifier The reserve <strong>Classifier</strong> to assign. 157 157 * @see org.greenstone.gatherer.cdm.DynamicListModel 158 158 */ 159 160 161 162 163 164 165 166 159 public void assignClassifier(Classifier classifier) { 160 if(!assigned.contains(classifier)) { 161 assigned.addElement(classifier); 162 classifier.setManager(this); 163 gatherer.c_man.configurationChanged(); 164 } 165 } 166 /** Method to assign a classifier. 167 167 * @param classifier The <strong>CustomClassifier</strong> to assign. 168 168 * @see org.greenstone.gatherer.cdm.DynamicListModel 169 169 */ 170 171 172 173 174 175 176 177 170 public void assignClassifier(CustomClassifier classifier) { 171 if(!assigned.contains(classifier)) { 172 assigned.addElement(classifier); 173 classifier.setManager(this); 174 gatherer.c_man.configurationChanged(); 175 } 176 } 177 /** Destructor. 178 178 * @see org.greenstone.gatherer.Gatherer 179 179 * @see org.greenstone.gatherer.cdm.CollectionDesignManager 180 180 * @see org.greenstone.gatherer.cdm.DynamicListModel 181 181 */ 182 183 184 185 186 187 188 189 190 191 192 193 194 195 182 public void destroy() { 183 // Deregister as a listener 184 if(gatherer.c_man != null && gatherer.c_man.msm != null) { 185 gatherer.c_man.msm.removeMSMListener(this); 186 } 187 // Null globals 188 assigned = null; 189 controls = null; 190 gatherer = null; 191 manager = null; 192 reserve = null; 193 unresolved_commands = null; 194 } 195 /** Method to retrieve the classifier with the given index. 196 196 * @param index The index of the desired classifier as an <i>int</i>. 197 197 * @return The requested Classifier as an <strong>Object</strong> or <i>null</i> if no such classifier exists. 198 198 * @see org.greenstone.gatherer.cdm.DynamicListModel 199 199 */ 200 201 202 203 204 205 206 200 public Object getClassifier(int index) { 201 if(0 <= index && index < assigned.size()) { 202 return assigned.get(index); 203 } 204 return null; 205 } 206 /** Method to retrieve the named classifier. 207 207 * @param name The name of the desired classifier as a <strong>String</strong>. 208 208 * @return The requested <strong>Classifier</strong> or <i>null</i> if no such classifier exists. 209 209 * @see org.greenstone.gatherer.cdm.DynamicListModel 210 210 */ 211 212 213 214 215 216 217 218 219 220 221 211 public Classifier getClassifier(String name) { 212 for(int i = 0; i < reserve.size(); i++) { 213 Classifier classifier = (Classifier)reserve.get(i); 214 if(classifier.getName().equals(name)) { 215 return classifier; 216 } 217 } 218 // No success. 219 return null; 220 } 221 /** Method to retrieve the control for this manager. 222 222 * @return A <strong>JPanel</strong> containing the controls. 223 223 */ 224 225 226 227 228 229 230 224 public JPanel getControls() { 225 if(controls == null) { 226 controls = new Control(); 227 } 228 return controls; 229 } 230 /** Called whenever a metadata element changes significantly. 231 231 * @param event A <strong>MSMEvent</strong> choc' full of event informationy goodness. 232 232 */ 233 234 235 236 233 public void elementChanged(MSMEvent event) { 234 // Don't really care, as the elements dealt with here are all live references so changes like identifier change will propagate immediately. 235 } 236 /** Method to find the index of the given classifier within the assigned classifiers. 237 237 * @param classifier The <strong>Classifier</strong> whose index you wish to find. 238 238 * @return The index of the classifier as an <i>int</i>, which has a value of -1 if the classifier was not found. 239 239 * @see org.greenstone.gatherer.cdm.DynamicListModel 240 240 */ 241 242 243 244 245 246 247 248 249 250 251 */ 252 253 254 255 256 257 258 241 public int indexOf(Classifier classifier) { 242 for(int i = 0; i < assigned.size(); i++) { 243 Classifier sibling = (Classifier) assigned.get(i); 244 if(sibling.equals(classifier)) { 245 return i; 246 } 247 } 248 return -1; 249 } 250 /** Method to invalidate controls after a significant change in the system state. 251 */ 252 public void invalidateControls() { 253 if(controls != null) { 254 controls.destroy(); 255 } 256 controls = null; 257 } 258 /** Method to load the details of a single plug-in. 259 259 * @param classifier The classifier <strong>File</strong> you wish to load. 260 260 */ 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 261 public void loadClassifier(File classifier) { 262 ///ystem.err.println("Attempting to parse " + classifier.toString()); 263 Document document = null; 264 long start; 265 long end; 266 // Run classinfo on this classifier, and then send the results for parsing. 267 try { 268 String args[] = null; 269 if(Utility.isWindows()) { 270 args = new String[4]; 271 if(Gatherer.config.perl_path != null) { 272 args[0] = gatherer.config.perl_path + "Perl.exe"; 273 } 274 else { 275 args[0] = "Perl.exe"; 276 } 277 args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl"; 278 args[2] = "-xml"; 279 args[3] = getClassifierName(classifier); 280 } 281 else { 282 args = new String[3]; 283 args[0] = "classinfo.pl"; 284 args[1] = "-xml"; 285 args[2] = getClassifierName(classifier); 286 } 287 287 288 288 // Create the process. 289 290 291 292 293 294 295 296 297 298 289 Runtime runtime = Runtime.getRuntime(); 290 Process process = runtime.exec(args); 291 InputStream input_stream = process.getErrorStream(); 292 BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream())); 293 String line = ""; 294 StringBuffer xml = new StringBuffer(""); 295 while((line = error_in.readLine()) != null) { 296 xml.append(line); 297 xml.append("\n"); 298 } 299 299 // Then read the xml from the piped input stream. 300 301 302 303 304 305 306 300 InputSource source = new InputSource(new StringReader(xml.toString())); 301 DOMParser parser = new DOMParser(); 302 parser.parse(source); 303 document = parser.getDocument(); 304 } 305 catch (Exception error) { 306 error.printStackTrace(); 307 307 //ystem.err.println("Error: Cannot parse " + getClassifierName(classifier)); 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 308 } 309 if(document != null) { 310 parse(document.getDocumentElement()); 311 } 312 } 313 /** Called whenever the metadata value associated to a certain record changes. */ 314 public void metadataChanged(MSMEvent event) { 315 FileNode record = event.getRecord(); 316 if(record != null) { 317 for(int i = 0; i < assigned.size(); i++) { 318 Object object = assigned.get(i); 319 if(object instanceof CustomClassifier) { 320 CustomClassifier classifier = (CustomClassifier) object; 321 classifier.process(record); 322 } 323 } 324 } 325 } 326 /** This method attempts to parse a classifier command from a command string taken from the collection configuration file. This process is quite complex as not only must the correct classifier be matched but also all of the parameters given must be legal. If such a command is found, the classifier is immediately assigned. 327 327 * @param command The command <strong>String</strong> that may include classifier information. 328 328 * @return <i>true</i> if a classifier command was parsed, <i>false</i> otherwise. … … 331 331 * @see org.greenstone.gatherer.cdm.CommandTokenizer 332 332 */ 333 public boolean parse(String command) { 334 String command_lc = command.toLowerCase(); 335 if(command_lc.startsWith("classify")) { 336 CommandTokenizer tokenizer = new CommandTokenizer(command); 337 if(tokenizer.countTokens() >= 2) { 338 tokenizer.nextToken(); // Throw away 'classifier' 339 String name = tokenizer.nextToken(); 340 // Try to locate the classifier with this name. 341 Classifier classifier = getClassifier(name); 342 // And if successful start to parse the arguments. 343 if(classifier != null) { 344 // Take a copy. 345 classifier = classifier.copy(); 346 String key = null; 347 while((key = tokenizer.nextToken()) != null) { 348 // Try to retrieve a matching argument. 349 Argument argument = classifier.getArgument(key); 350 if(argument != null) { 351 // Set as assigned. 352 argument.setAssigned(true); 353 // And if the argument is of a parameter type, parse a parameter. 354 if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) { 355 String value = tokenizer.nextToken(); 356 value = value.replace(':', MSMUtils.NS_SEP); 357 argument.setValue(value); 358 } 359 } 360 // Argument cannot be matched. 361 else { 362 String cur_key = key; 363 String value = tokenizer.nextToken(); 364 if(value.startsWith("-")) { 365 key = value; 366 value = null; 367 } 368 else { 369 key = null; 370 } 371 String custom = classifier.getCustom(); 372 if(custom == null) { 373 if(value == null) { 374 classifier.setCustom(cur_key); 375 } 376 else { 377 classifier.setCustom(cur_key + " " + value); 378 } 379 } 380 else { 381 if(value == null) { 382 classifier.setCustom(custom + " " + cur_key); 383 } 384 else { 385 classifier.setCustom(custom + " " + cur_key + " " + value); 386 } 387 } 388 } 389 } 390 assignClassifier(classifier); 391 return true; 392 } 393 else { 394 ///ystem.err.println("Unknown classifier"); 395 } 333 public boolean parse(String command) { 334 String command_lc = command.toLowerCase(); 335 if(command_lc.startsWith("classify")) { 336 CommandTokenizer tokenizer = new CommandTokenizer(command); 337 if(tokenizer.countTokens() >= 2) { 338 tokenizer.nextToken(); // Throw away 'classifier' 339 String name = tokenizer.nextToken(); 340 // Try to locate the classifier with this name. 341 Classifier classifier = getClassifier(name); 342 // And if successful start to parse the arguments. 343 if(classifier != null) { 344 // Take a copy. 345 classifier = classifier.copy(); 346 String key = null; 347 while((key = tokenizer.nextToken()) != null) { 348 // Try to retrieve a matching argument. 349 Argument argument = classifier.getArgument(key); 350 if(argument != null) { 351 // Set as assigned. 352 argument.setAssigned(true); 353 // And if the argument is of a parameter type, parse a parameter. 354 if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) { 355 String value = tokenizer.nextToken(); 356 value = value.replace(':', MSMUtils.NS_SEP); 357 argument.setValue(value); 358 } 359 } 360 // Argument cannot be matched. 361 else { 362 String cur_key = key; 363 String value = tokenizer.nextToken(); 364 if(value.startsWith("-")) { 365 key = value; 366 value = null; 367 } 368 else { 369 key = null; 370 } 371 String custom = classifier.getCustom(); 372 if(custom == null) { 373 if(value == null) { 374 classifier.setCustom(cur_key); 396 375 } 397 } 398 else if(command_lc.startsWith("customclassifier")) { 399 unresolved_commands.add(command); 400 return true; 401 } 402 return false; 403 } 404 /** This method removes an assigned classifier. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a classifier from the reserve. 376 else { 377 classifier.setCustom(cur_key + " " + value); 378 } 379 } 380 else { 381 if(value == null) { 382 classifier.setCustom(custom + " " + cur_key); 383 } 384 else { 385 classifier.setCustom(custom + " " + cur_key + " " + value); 386 } 387 } 388 } 389 } 390 assignClassifier(classifier); 391 return true; 392 } 393 else { 394 ///ystem.err.println("Unknown classifier"); 395 } 396 } 397 } 398 else if(command_lc.startsWith("customclassifier")) { 399 unresolved_commands.add(command); 400 return true; 401 } 402 return false; 403 } 404 /** This method removes an assigned classifier. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a classifier from the reserve. 405 405 * @param classifier The Classifier or CustomClassifier, as an <strong>Object</strong>, to remove. 406 406 * @see org.greenstone.gatherer.cdm.DynamicListModel 407 407 */ 408 409 410 411 412 408 public void removeClassifier(Object classifier) { 409 assigned.removeElement(classifier); 410 gatherer.c_man.configurationChanged(); 411 } 412 /** Method which attempts to reparse obvious classifier commands which previously referenced unresovable Classifiers. 413 413 * @see org.greenstone.gatherer.cdm.Classifier 414 414 * @see org.greenstone.gatherer.cdm.CommandTokenizer 415 415 * @see org.greenstone.gatherer.cdm.CustomClassifier 416 416 */ 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 417 public void reparseUnresolved() { 418 for(int i = 0; i < unresolved_commands.size(); i++) { 419 String command = (String) unresolved_commands.get(i); 420 CommandTokenizer tokenizer = new CommandTokenizer(command); 421 if(tokenizer.countTokens() >= 6) { 422 tokenizer.nextToken();// Loose customclassifier 423 // Get class name. 424 String class_name = tokenizer.nextToken(); 425 // Parse arguments. 426 String replaces = null; 427 String separations = null; 428 while(tokenizer.hasMoreTokens()) { 429 String arg_name = tokenizer.nextToken(); 430 if(arg_name.equalsIgnoreCase("-replaces")) { 431 replaces = tokenizer.nextToken(); 432 } 433 else { 434 separations = tokenizer.nextToken(); 435 } 436 } 437 try { 438 replaces = replaces.substring(2); 439 int index = Integer.parseInt(replaces); 440 Classifier original = (Classifier)getClassifier(index); 441 if(original != null) { 442 Class custom_classifier_class = Class.forName("org.greenstone.gatherer.cdm.custom." + class_name); 443 CustomClassifier custom_classifier = (CustomClassifier) custom_classifier_class.newInstance(); 444 custom_classifier.setGatherer(gatherer); 445 custom_classifier.recreate(original, separations); 446 assigned.add(indexOf(original), custom_classifier); 447 assigned.removeElement(original); 448 } 449 else { 450 ///ystem.err.println("Missing original."); 451 } 452 } 453 catch (Exception error) { 454 error.printStackTrace(); 455 } 456 } 457 } 458 // Regardless of if they work, clear the commands. 459 unresolved_commands.clear(); 460 } 461 /** Method to cache the current contents of reserve (known classifiers) to file. 462 462 * @see org.greenstone.gatherer.util.Utility 463 463 */ 464 465 466 467 468 469 470 471 472 473 474 464 public void saveClassifiers() { 465 try { 466 FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat"); 467 ObjectOutputStream out = new ObjectOutputStream(file); 468 out.writeObject(reserve); 469 out.close(); 470 } 471 catch (Exception error) { 472 } 473 } 474 /** Called when a metadata set changed significantly. 475 475 * @param event A <strong>MSMEvent</strong> containing information about the set change. 476 476 */ 477 478 479 480 477 public void setChanged(MSMEvent event) { 478 // Again, we would only worry about this if we contained 'inanimate' references to elements or something, but our references are live, and controls are rebuilt everytime a pop-up is needed. 479 } 480 /** Method used to determine the number of classifiers that have been assigned. 481 481 * @return An <i>int</i> which is the number of classifiers. 482 482 */ 483 484 485 486 483 public int size() { 484 return assigned.size(); 485 } 486 /** Method to print out a block of classifier commands, much like you'd find in a collection configuration file. 487 487 * @return A <strong>String</strong> containing a series of classifier commands separated by new lines. 488 488 * @see org.greenstone.gatherer.cdm.Classifier 489 489 * @see org.greenstone.gatherer.cdm.CustomClassifier 490 490 */ 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 491 public String toString() { 492 StringBuffer text = new StringBuffer(); 493 for(int i = 0; i < assigned.size(); i++) { 494 Object object = assigned.get(i); 495 if(object instanceof Classifier) { 496 Classifier classifier = (Classifier) object; 497 text.append(classifier.toString()); 498 } 499 else if(object instanceof CustomClassifier) { 500 CustomClassifier classifier = (CustomClassifier) object; 501 text.append(classifier.getCommand()); 502 text.append("\n"); 503 text.append(classifier.getCustomCommand(i)); 504 } 505 text.append("\n"); 506 } 507 text.append("\n"); 508 return text.toString(); 509 } 510 /** Called when a significant change has occured to a value tree for a certain element, however we take no further action. 511 511 * @param event A <strong>MSMEvent</strong> containing information relevant to the event. 512 512 */ 513 514 515 513 public void valueChanged(MSMEvent event) { 514 } 515 /** Retrieve a phrase from the dictionary based on a certain key. 516 516 * @param key The search <strong>String</strong>. 517 517 * @return The matching phrase from the Dictionary. 518 518 */ 519 520 521 522 519 private String get(String key) { 520 return get(key, null); 521 } 522 /** Retrieve a phrase from the dictionary based on a certain key and certain arguments. 523 523 * @param key The search <strong>String</strong>. 524 524 * @param args A <strong>String[]</strong> used to complete and format the returned phrase. … … 527 527 * @see org.greenstone.gatherer.Gatherer 528 528 */ 529 530 531 532 533 534 535 529 private String get(String key, String args[]) { 530 if(key.indexOf(".") == -1) { 531 key = "CDM.ClassifierManager." + key; 532 } 533 return gatherer.dictionary.get(key, args); 534 } 535 /** Method to extract just the classifiers name from a file object. 536 536 * @param classifier The <strong>File</strong> which references a certain classifier. 537 537 * @return A <strong>String</strong> containing just the classifiers name, without extension. 538 538 */ 539 540 541 542 543 544 545 546 539 private String getClassifierName(File classifier) { 540 String name = classifier.getName(); 541 if(name.indexOf(".") != -1) { 542 name = name.substring(0, name.indexOf(".")); 543 } 544 return name; 545 } 546 /** Method to initially load information from the standard plug-ins within the gsdl Perl library. 547 547 * @see org.greenstone.gatherer.cdm.DynamicListModel 548 548 * @see org.greenstone.gatherer.util.Utility 549 549 */ 550 551 552 553 554 555 556 557 558 559 560 550 private void loadClassifiers() { 551 // Attempt to restore the cached file. 552 try { 553 FileInputStream file = new FileInputStream(Utility.BASE_DIR + "classifiers.dat"); 554 ObjectInputStream input = new ObjectInputStream(file); 555 reserve = (DynamicListModel) input.readObject(); 556 } 557 catch (Exception error) { 558 } 559 if(reserve == null) { 560 reserve = new DynamicListModel(); 561 561 // Retrieve the gsdl home directory... 562 563 564 565 566 567 562 String directory = gatherer.config.gsdl_path; 563 directory = directory + "perllib" + File.separator + "classify" + File.separator; 564 loadClassifiers(new File(directory)); 565 } 566 } 567 /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location. 568 568 * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins. 569 569 * @see org.greenstone.gatherer.cdm.ParsingProgress 570 570 */ 571 572 573 571 private void loadClassifiers(File directory) { 572 File files[] = directory.listFiles(); 573 if(files != null) { 574 574 // Create a progress indicator. 575 576 577 578 579 580 581 582 583 584 585 586 587 588 575 ParsingProgress progress = new ParsingProgress(get("CDM.ClassifierManager.Parsing.Title"), get("CDM.ClassifierManager.Parsing.Message"), files.length); 576 for(int i = 0; i < files.length; i++) { 577 // We only want to check Perl Modules. 578 if(files[i].getName().endsWith(".pm")) { 579 loadClassifier(files[i]); 580 } 581 progress.inc(); 582 } 583 progress.dispose(); 584 progress.destroy(); 585 progress = null; 586 } 587 } 588 /** Parses a DOM tree model turning it into a Classifier and its associated arguments. 589 589 * @param root The <strong>Node</strong> at the root of the DOM model. 590 590 * @return A newly created <strong>Classifier</strong> based on the information parsed from the DOM model. 591 591 * @see org.greenstone.gatherer.cdm.Argument 592 592 */ 593 private Classifier parse(Node root) { 594 Classifier classifier = new Classifier(); 595 String node_name = null; 596 for(Node node = root.getFirstChild(); node != null; 597 node = node.getNextSibling()) { 598 node_name = node.getNodeName(); 599 if(node_name.equals("Name")) { 600 String name = MSMUtils.getValue(node); 601 // We can save ourselves some processing time if a classifier with this name already exists in our manager. If so retrieve it and return it. 602 Classifier existing = getClassifier(name); 603 if(existing != null) { 604 return existing; 605 } 606 classifier.setName(name); 593 private Classifier parse(Node root) { 594 Classifier classifier = new Classifier(); 595 String node_name = null; 596 for(Node node = root.getFirstChild(); node != null; 597 node = node.getNextSibling()) { 598 node_name = node.getNodeName(); 599 if(node_name.equals("Name")) { 600 String name = MSMUtils.getValue(node); 601 // We can save ourselves some processing time if a classifier with this name already exists in our manager. If so retrieve it and return it. 602 Classifier existing = getClassifier(name); 603 if(existing != null) { 604 return existing; 605 } 606 classifier.setName(name); 607 } 608 else if(node_name.equals("Desc")) { 609 classifier.setDesc(MSMUtils.getValue(node)); 610 } 611 // Parse the multitude of arguments. 612 else if(node_name.equals("Arguments")) { 613 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) { 614 node_name = arg.getNodeName(); 615 // An option. 616 if(node_name.equals("Option")) { 617 Argument argument = new Argument(); 618 // If its an option we parse the multitude of details an options might have. 619 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) { 620 node_name = det.getNodeName(); 621 if(node_name.equals("Name")) { 622 argument.setName(MSMUtils.getValue(det)); 623 } 624 else if(node_name.equals("Desc")) { 625 argument.setDesc(MSMUtils.getValue(det)); 626 } 627 else if(node_name.equals("Type")) { 628 argument.setType(MSMUtils.getValue(det)); 629 } 630 else if(node_name.equals("Default")) { 631 argument.setDefault(MSMUtils.getValue(det)); 632 } 633 else if(node_name.equals("List")) { 634 // Two final loops are required to parse lists. 635 for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) { 636 if(value.getNodeName().equals("Value")) { 637 String key = null; 638 String desc = ""; 639 for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) { 640 node_name = subvalue.getNodeName(); 641 if(node_name.equals("Name")) { 642 key = MSMUtils.getValue(subvalue); 643 } 644 else if(node_name.equals("Desc")) { 645 desc = MSMUtils.getValue(subvalue); 646 } 647 } 648 if(key != null) { 649 argument.addOption(key, desc); 650 } 651 } 607 652 } 608 else if(node_name.equals("Desc")) { 609 classifier.setDesc(MSMUtils.getValue(node)); 653 } 654 else if(node_name.equals("Required")) { 655 String v = MSMUtils.getValue(det); 656 ///ystem.err.println("Required = " + v); 657 if(v.equalsIgnoreCase("yes")) { 658 ///ystem.err.println("Setting required to true."); 659 argument.setRequired(true); 610 660 } 611 // Parse the multitude of arguments. 612 else if(node_name.equals("Arguments")) { 613 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) { 614 node_name = arg.getNodeName(); 615 // An option. 616 if(node_name.equals("Option")) { 617 Argument argument = new Argument(); 618 // If its an option we parse the multitude of details an options might have. 619 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) { 620 node_name = det.getNodeName(); 621 if(node_name.equals("Name")) { 622 argument.setName(MSMUtils.getValue(det)); 623 } 624 else if(node_name.equals("Desc")) { 625 argument.setDesc(MSMUtils.getValue(det)); 626 } 627 else if(node_name.equals("Type")) { 628 argument.setType(MSMUtils.getValue(det)); 629 } 630 else if(node_name.equals("Default")) { 631 argument.setDefault(MSMUtils.getValue(det)); 632 } 633 else if(node_name.equals("List")) { 634 // Two final loops are required to parse lists. 635 for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) { 636 if(value.getNodeName().equals("Value")) { 637 String key = null; 638 String desc = ""; 639 for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) { 640 node_name = subvalue.getNodeName(); 641 if(node_name.equals("Name")) { 642 key = MSMUtils.getValue(subvalue); 643 } 644 else if(node_name.equals("Desc")) { 645 desc = MSMUtils.getValue(subvalue); 646 } 647 } 648 if(key != null) { 649 argument.addOption(key, desc); 650 } 651 } 652 } 653 } 654 else if(node_name.equals("Required")) { 655 String v = MSMUtils.getValue(det); 656 ///ystem.err.println("Required = " + v); 657 if(v.equalsIgnoreCase("yes")) { 658 ///ystem.err.println("Setting required to true."); 659 argument.setRequired(true); 660 } 661 } 662 } 663 classifier.addArgument(argument); 664 } 665 // A super classifier class. 666 else if(node_name.equals("ClasInfo")) { 667 Classifier super_classifier = parse(arg); 668 classifier.setSuper(super_classifier); 669 } 670 } 671 } 672 } 673 if(classifier.getName() != null) { 674 addClassifier(classifier); 675 return classifier; 676 } 677 return null; 678 } 679 /** A class which provides controls for assigned and editing classifiers. */ 680 private class Control 681 extends JPanel { 682 /** Button for adding classifiers. */ 683 private JButton add = null; 684 /** Button for configuring the selected classifier. */ 685 private JButton configure = null; 686 /** Button to remove the selected classifier. */ 687 private JButton remove = null; 688 /** A combobox containing all of the known classifiers, including those that may have already been assigned. */ 689 private JComboBox classifier = null; 690 /** A list of assigned classifiers. */ 691 private JList classifier_list = null; 692 /** The text area containing instructions on the use of this control. */ 693 private JTextArea instructions = null; 694 /** Constructor. 695 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.AddListener 696 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.ConfigureListener 697 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.RemoveListener 661 } 662 } 663 classifier.addArgument(argument); 664 } 665 // A super classifier class. 666 else if(node_name.equals("ClasInfo")) { 667 Classifier super_classifier = parse(arg); 668 classifier.setSuper(super_classifier); 669 } 670 } 671 } 672 } 673 if(classifier.getName() != null) { 674 addClassifier(classifier); 675 return classifier; 676 } 677 return null; 678 } 679 /** A class which provides controls for assigned and editing classifiers. */ 680 private class Control 681 extends JPanel { 682 /** Button for adding classifiers. */ 683 private JButton add = null; 684 /** Button for configuring the selected classifier. */ 685 private JButton configure = null; 686 /** Button to remove the selected classifier. */ 687 private JButton remove = null; 688 /** A combobox containing all of the known classifiers, including those that may have already been assigned. */ 689 private JComboBox classifier = null; 690 /** A list of assigned classifiers. */ 691 private JList classifier_list = null; 692 /** The text area containing instructions on the use of this control. */ 693 private JTextArea instructions = null; 694 /** Constructor. 695 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.AddListener 696 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.ConfigureListener 697 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.RemoveListener 698 */ 699 public Control() { 700 Object classifiers[] = reserve.toArray(); 701 ArrayList classifier_model = new ArrayList(); 702 for(int i = 0; i < classifiers.length; i++) { 703 classifier_model.add(((Classifier)classifiers[i]).getName()); 704 } 705 // Now we add custom classifiers. 706 addCustomClassifiers(classifier_model); 707 Collections.sort(classifier_model); 708 // Create 709 add = new JButton(get("Add")); 710 JPanel button_pane = new JPanel(); 711 JPanel central_pane = new JPanel(); 712 configure = new JButton(get("Configure")); 713 JPanel header_pane = new JPanel(); 714 instructions = new JTextArea(get("Instructions")); 715 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false)); 716 instructions.setEditable(false); 717 instructions.setLineWrap(true); 718 instructions.setRows(5); 719 instructions.setWrapStyleWord(true); 720 classifier = new JComboBox(classifier_model.toArray()); 721 classifier.setEditable(true); 722 JLabel classifier_label = new JLabel(get("Classifier")); 723 classifier_list = new JList(assigned); 724 JLabel classifier_list_label = new JLabel(get("Assigned")); 725 classifier_list_label.setHorizontalAlignment(JLabel.CENTER); 726 classifier_list_label.setOpaque(true); 727 JPanel classifier_list_pane = new JPanel(); 728 JPanel classifier_pane = new JPanel(); 729 remove = new JButton(get("Remove")); 730 JLabel title = new JLabel(get("Title")); 731 title.setHorizontalAlignment(JLabel.CENTER); 732 title.setOpaque(true); 733 JPanel temp = new JPanel(new BorderLayout()); 734 // Listeners 735 add.addActionListener(new AddListener()); 736 configure.addActionListener(new ConfigureListener()); 737 remove.addActionListener(new RemoveListener()); 738 classifier_list.addMouseListener(new ClickListener()); 739 // Layout 740 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0)); 741 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5)); 742 header_pane.setLayout(new BorderLayout()); 743 header_pane.add(title, BorderLayout.NORTH); 744 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER); 745 classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2)); 746 classifier_list_pane.setLayout(new BorderLayout()); 747 classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH); 748 classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER); 749 classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); 750 classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); 751 classifier_pane.setLayout(new GridLayout(1,2)); 752 classifier_pane.add(classifier_label); 753 classifier_pane.add(classifier); 754 button_pane.setLayout(new GridLayout(3,1)); 755 button_pane.add(add); 756 button_pane.add(configure); 757 button_pane.add(remove); 758 // Scope these mad bordering skillz. 759 temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2)))); 760 temp.add(classifier_pane, BorderLayout.NORTH); 761 temp.add(button_pane, BorderLayout.SOUTH); 762 central_pane.setLayout(new BorderLayout()); 763 central_pane.add(classifier_list_pane, BorderLayout.CENTER); 764 central_pane.add(temp, BorderLayout.SOUTH); 765 setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 766 setLayout(new BorderLayout()); 767 add(header_pane, BorderLayout.NORTH); 768 add(central_pane, BorderLayout.CENTER); 769 } 770 /** Method which acts like a destructor, tidying up references to persistant objects. 698 771 */ 699 public Control() { 700 Object classifiers[] = reserve.toArray(); 701 ArrayList classifier_model = new ArrayList(); 702 for(int i = 0; i < classifiers.length; i++) { 703 classifier_model.add(((Classifier)classifiers[i]).getName()); 704 } 705 // Now we add custom classifiers. 706 addCustomClassifiers(classifier_model); 707 Collections.sort(classifier_model); 708 // Create 709 add = new JButton(get("Add")); 710 JPanel button_pane = new JPanel(); 711 JPanel central_pane = new JPanel(); 712 configure = new JButton(get("Configure")); 713 JPanel header_pane = new JPanel(); 714 instructions = new JTextArea(get("Instructions")); 715 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false)); 716 instructions.setEditable(false); 717 instructions.setLineWrap(true); 718 instructions.setRows(5); 719 instructions.setWrapStyleWord(true); 720 classifier = new JComboBox(classifier_model.toArray()); 721 classifier.setEditable(true); 722 JLabel classifier_label = new JLabel(get("Classifier")); 723 classifier_list = new JList(assigned); 724 JLabel classifier_list_label = new JLabel(get("Assigned")); 725 classifier_list_label.setHorizontalAlignment(JLabel.CENTER); 726 classifier_list_label.setOpaque(true); 727 JPanel classifier_list_pane = new JPanel(); 728 JPanel classifier_pane = new JPanel(); 729 remove = new JButton(get("Remove")); 730 JLabel title = new JLabel(get("Title")); 731 title.setHorizontalAlignment(JLabel.CENTER); 732 title.setOpaque(true); 733 JPanel temp = new JPanel(new BorderLayout()); 734 // Listeners 735 add.addActionListener(new AddListener()); 736 configure.addActionListener(new ConfigureListener()); 737 remove.addActionListener(new RemoveListener()); 738 classifier_list.addMouseListener(new ClickListener()); 739 // Layout 740 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0)); 741 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5)); 742 header_pane.setLayout(new BorderLayout()); 743 header_pane.add(title, BorderLayout.NORTH); 744 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER); 745 classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2)); 746 classifier_list_pane.setLayout(new BorderLayout()); 747 classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH); 748 classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER); 749 classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); 750 classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); 751 classifier_pane.setLayout(new GridLayout(1,2)); 752 classifier_pane.add(classifier_label); 753 classifier_pane.add(classifier); 754 button_pane.setLayout(new GridLayout(3,1)); 755 button_pane.add(add); 756 button_pane.add(configure); 757 button_pane.add(remove); 758 // Scope these mad bordering skillz. 759 temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2)))); 760 temp.add(classifier_pane, BorderLayout.NORTH); 761 temp.add(button_pane, BorderLayout.SOUTH); 762 central_pane.setLayout(new BorderLayout()); 763 central_pane.add(classifier_list_pane, BorderLayout.CENTER); 764 central_pane.add(temp, BorderLayout.SOUTH); 765 setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 766 setLayout(new BorderLayout()); 767 add(header_pane, BorderLayout.NORTH); 768 add(central_pane, BorderLayout.CENTER); 769 } 770 /** Method which acts like a destructor, tidying up references to persistant objects. 772 public void destroy() { 773 add = null; 774 classifier = null; 775 classifier_list = null; 776 configure = null; 777 instructions = null; 778 remove = null; 779 } 780 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called. 771 781 */ 772 public void destroy() { 773 add = null; 774 classifier = null; 775 classifier_list = null; 776 configure = null; 777 instructions = null; 778 remove = null; 779 } 780 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called. 781 */ 782 public void updateUI() { 783 if(instructions != null) { 784 instructions.setCaretPosition(0); 785 } 786 super.updateUI(); 787 } 788 /** Searches and adds a list of dynamically located CustomClassifiers. Note that the classes must be located under org.greenstone.gatherer.cdm.custom and have accompaning properties files which are used as dictionaries. 782 public void updateUI() { 783 if(instructions != null) { 784 instructions.setCaretPosition(0); 785 } 786 super.updateUI(); 787 } 788 /** Searches and adds a list of dynamically located CustomClassifiers. Note that the classes must be located under org.greenstone.gatherer.cdm.custom and have accompaning properties files which are used as dictionaries. 789 789 * @param classifier_model An <strong>ArrayList</strong> which will be used as the model for the combobox listing all known Classifiers. 790 790 */ 791 791 private void addCustomClassifiers(ArrayList classifier_model) { 792 792 //classifier_model.add("CustomAZList"); 793 793 // Search for classifiers under the org.greenstone.gatherer.cdm.custom directory. 794 795 796 797 798 799 800 801 802 803 804 805 806 807 794 File custom_directory = new File(Utility.BASE_DIR + "classes" + File.separator + "org" + File.separator + "greenstone" + File.separator + "gatherer" + File.separator + "cdm" + File.separator + "custom"); 795 if(custom_directory.exists()) { 796 File children[] = custom_directory.listFiles(); 797 for(int i = 0; i < children.length; i++) { 798 String temp = children[i].getName().toLowerCase(); 799 // There are a whole bunch of conditions about what files are custom classifier main classes. 800 if(temp.endsWith(".class") && temp.indexOf("$") == -1) { 801 // Determine the name of this custom classifier. 802 String name = children[i].getName(); 803 name = name.substring(0, name.indexOf(".")); 804 classifier_model.add(name); 805 } 806 } 807 } 808 808 // Search for any other CustomClassifiers within the jar file (if present) 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 809 File jar_file = new File("Gatherer.jar"); 810 if(jar_file.exists()) { 811 try { 812 JarFile jar = new JarFile(jar_file); 813 for(Enumeration entries = jar.entries(); entries.hasMoreElements(); ) { 814 String name = entries.nextElement().toString(); 815 if(name.startsWith("org/greenstone/gatherer/cdm/custom/") && name.endsWith(".class") && name.indexOf("$") == -1) { 816 name = name.substring(35, name.length() - 6); 817 if(!classifier_model.contains(name)) { 818 classifier_model.add(name); 819 } 820 } 821 name = null; 822 } 823 jar = null; 824 } 825 catch (Exception error) { 826 error.printStackTrace(); 827 } 828 } 829 jar_file = null; 830 } 831 /** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method. 832 832 */ 833 834 833 private class AddListener 834 implements ActionListener { 835 835 /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls, so that we can add the selected Classifier. 836 836 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action. … … 840 840 * @see org.greenstone.gatherer.cdm.CustomClassifier 841 841 */ 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 842 public void actionPerformed(ActionEvent event) { 843 String name = (String)classifier.getSelectedItem(); 844 Classifier target = getClassifier(name); 845 Classifier classifier = null; 846 CustomClassifier custom_classifier = null; 847 if(target != null) { 848 classifier = target.copy(); 849 } 850 else { 851 // Try to retrieve custom classifier for name. 852 try { 853 Class custom_class = Class.forName("org.greenstone.gatherer.cdm.custom." + name); 854 custom_classifier = (CustomClassifier)custom_class.newInstance(); 855 custom_classifier.setGatherer(gatherer); 856 } 857 catch (Exception error) { 858 gatherer.debug(error, "Error in ClassifierManager.AddListener.actionPerformed(): " + error); 859 } 860 // And if all else fails create a new classifier. 861 if(classifier == null && custom_classifier == null) { 862 classifier = new Classifier(name, "", null); 863 } 864 } 865 if(classifier != null) { 866 // Automatically chain to configuration. This ensures required arguments are filled out. 867 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, classifier); 868 if(ac.display()) { 869 assignClassifier(classifier); 870 } 871 ac.destroy(); 872 ac = null; 873 } 874 // Custom classifier 875 else { 876 if(custom_classifier.display(true)) { 877 assignClassifier(custom_classifier); 878 } 879 custom_classifier.destroy(); // Remove gui prompt or else. 880 custom_classifier = null; 881 } 882 } 883 } 884 /** Listens for double clicks apon the list and react as if the configure button was pushed. */ 885 private class ClickListener 886 extends MouseAdapter { 887 887 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt. 888 888 * @param event A <strong>MouseEvent</strong> containing information about the mouse click. 889 889 */ 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 890 public void mouseClicked(MouseEvent event) { 891 if(event.getClickCount() == 2 ) { 892 if(!classifier_list.isSelectionEmpty()) { 893 Object object = classifier_list.getSelectedValue(); 894 if(object instanceof Classifier) { 895 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object); 896 if(ac.display()) { 897 assigned.refresh(); 898 } 899 ac.destroy(); 900 ac = null; 901 } 902 else if(object instanceof CustomClassifier) { 903 CustomClassifier cc = (CustomClassifier)object; 904 if(cc.display(true)) { 905 assigned.refresh(); 906 } 907 cc.destroy(); // Remove gui prompt or else. 908 cc = null; 909 } 910 } 911 } 912 } 913 } 914 /** This class listens for actions upon the configure button in the controls, and if detected creates a new ArgumentConfiguration dialog box to allow for configuration. 915 915 */ 916 917 916 private class ConfigureListener 917 implements ActionListener { 918 918 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls. 919 919 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action. … … 922 922 * @see org.greenstone.gatherer.cdm.CustomClassifier 923 923 */ 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 924 public void actionPerformed(ActionEvent event) { 925 if(!classifier_list.isSelectionEmpty()) { 926 Object object = classifier_list.getSelectedValue(); 927 if(object instanceof Classifier) { 928 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object); 929 if(ac.display()) { 930 assigned.refresh(); 931 } 932 ac.destroy(); 933 ac = null; 934 } 935 else if(object instanceof CustomClassifier) { 936 CustomClassifier cc = (CustomClassifier)object; 937 if(cc.display(true)) { 938 assigned.refresh(); 939 } 940 cc.destroy(); // Remove gui prompt or else. 941 cc = null; 942 } 943 } 944 } 945 } 946 /** This class listens for actions upon the remove button in the controls, and if detected calls the removeClassifier() method. 947 947 */ 948 949 948 private class RemoveListener 949 implements ActionListener { 950 950 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls, so we can remove the selected Classifier. 951 951 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action. … … 953 953 * @see org.greenstone.gatherer.cdm.CustomClassifier 954 954 */ 955 956 957 958 959 960 961 962 963 964 955 public void actionPerformed(ActionEvent event) { 956 if(!classifier_list.isSelectionEmpty()) { 957 Object object = classifier_list.getSelectedValue(); 958 if(object instanceof Classifier || object instanceof CustomClassifier) { 959 removeClassifier(object); 960 } 961 } 962 } 963 } 964 } 965 965 } 966 966
Note:
See TracChangeset
for help on using the changeset viewer.