Changeset 4363 for trunk/gli/src/org/greenstone/gatherer/cdm
- Timestamp:
- 2003-05-27T15:34:50+12:00 (21 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/gli/src/org/greenstone/gatherer/cdm/custom/CustomAZList.java
r4293 r4363 61 61 */ 62 62 final public class CustomAZList 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 63 implements CustomClassifier { 64 /** When this the control dialog is disposed, should we go ahead a add this custom AZ list (by processing all file records and building a new hierarchy)? */ 65 private boolean process = false; 66 /** A reference to the Gatherer for access to the Collection and MetadataSetManager. */ 67 private Gatherer gatherer = null; 68 /** A mapping from a String pattern to a specific GValueNode within the hidden hierarchy. */ 69 private Hashtable mappings = null; 70 /** The button used to cancel the dialog. */ 71 private JButton cancel = null; 72 /** The button used to confirm and close the dialog. */ 73 private JButton ok = null; 74 /** The dialog which contains the controls for configuring this custom classifier. */ 75 private JDialog controls = null; 76 /** The checkbox used to indicate whether there is a name given for the classifier button (in the Greenstone collections menubar). */ 77 private JCheckBox buttonname_label = null; 78 /** The checkbox used to indicate that the final classifier should be sorted in some way. */ 79 private JCheckBox sort_label = null; 80 /** The control allowing you to choose the assigned metadata this classifier should be based on. */ 81 private JComboBox metadata = null; 82 /** The metadata the final classifier should be sorted by. */ 83 private JComboBox sort = null; 84 /** A field for entering the button name. */ 85 private JTextField buttonname = null; 86 /** A field which provides a clear indication of the current ranges selected for your custom classifier. */ 87 private JTextField separators_preview = null; 88 /** An array of togglebuttons showing what separations are available. */ 89 private JToggleButton separators[] = null; 90 /** A private dictionary for this custom classifier. */ 91 private ResourceBundle dictionary = null; 92 /** The name of the hidden metadata. We at least luck out in that we don't need a live reference to the metadata, because the user can never change it (or if they do its their own stinking fault). */ 93 private String hidden_mde_name = null; 94 /** The name of this pseudo-classifier. */ 95 final static public String NAME = "CustomAZList"; 96 /** The size of a label. */ 97 final static private Dimension LABEL_SIZE = new Dimension(200,25); 98 /** The size of the controls for this pseudo-classifier. */ 99 final static private Dimension SIZE = new Dimension(550,400); 100 /** An array of values for the separators. */ 101 final static private String VALUES[] = {"Numbers", "A", "B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}; 102 /** The same array as above, except as integer values (note that "Numbers" becomes "#"). */ 103 static public int INT_VALUES[] = {'#','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; 104 /** A third array which is almost the same as the others (can anyone else say poor code reuse) but subsitutes "#" for "Numbers". */ 105 static public String STRING_VALUES[] = {"#","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}; 106 /** Default Constructor. Needed to load this class dynamically. */ 107 public CustomAZList() {} 108 /** Constructor. 109 109 * @param gatherer A reference to the <strong>Gatherer</strong>. 110 110 */ 111 112 113 114 111 public CustomAZList(Gatherer gatherer) { 112 this.gatherer = gatherer; 113 } 114 /** Used to compare this classifier to another classifier for the purposes of ordering. 115 115 * @param object The other classifier as an <strong>Object</strong>. 116 116 * @see org.greenstone.gatherer.cdm.Classifier 117 117 * @see org.greenstone.gatherer.cdm.CustomClassifier 118 118 */ 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 119 public int compareTo(Object object) { 120 if(object instanceof Classifier) { 121 Classifier classifier = (Classifier) object; 122 return NAME.compareTo(classifier.getName()); 123 } 124 else if(object instanceof CustomClassifier) { 125 CustomClassifier classifier = (CustomClassifier) object; 126 return NAME.compareTo(classifier.getName()); 127 } 128 return NAME.compareTo(object.toString()); 129 } 130 /** Ensure that the dialog can be correctly garbage collected. */ 131 public void destroy() { 132 controls = null; 133 } 134 /** Produce a new copy of this custom classifier. Remember that what the classifier manager does is create instances of all possible classifiers, then as they are assigned creates and assigns copies of the original reserve. This way we only have to parse arguments once. 135 135 * @return A new <strong>CustomClassifier</strong> which is a copy of this one. 136 136 * @see org.greenstone.gatherer.Gatherer 137 137 */ 138 139 140 141 138 public CustomClassifier copy() { 139 return new CustomAZList(gatherer); 140 } 141 /** Show the controls for configuring this pseudo-classifier. 142 142 * @param show <i>true</i> to actually display the configuration dialog on screen, <i>false</i> to do everything except show the control and process the data (useful for setting the control up and/or reloading custom classifiers from collect.cfg). 143 143 * @see org.greenstone.gatherer.Configuration … … 152 152 * @see org.greenstone.gatherer.msm.MetadataSetManager 153 153 */ 154 155 156 154 public boolean display(boolean show) { 155 if(controls == null) { 156 Vector elements = gatherer.c_man.getCollection().msm.getAssignedElements(); 157 157 // Creation 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 158 controls = new JDialog(); 159 controls.setModal(true); 160 controls.setSize(SIZE); 161 controls.setTitle(get("Title_JDialog")); 162 JPanel content_pane = (JPanel) controls.getContentPane(); 163 JPanel upper_pane = new JPanel(); 164 JPanel metadata_pane = new JPanel(); 165 JLabel metadata_label = new JLabel(get("Metadata_JLabel")); 166 metadata_label.setPreferredSize(LABEL_SIZE); 167 metadata = new JComboBox(elements); 168 JPanel buttonname_pane = new JPanel(); 169 buttonname_label = new JCheckBox(get("Buttonname_JCheckBox")); 170 buttonname_label.setPreferredSize(LABEL_SIZE); 171 buttonname = new JTextField(); 172 buttonname.setBackground(Color.lightGray); 173 buttonname.setEnabled(false); 174 JPanel sort_pane = new JPanel(); 175 sort_label = new JCheckBox(get("Sort_JLabel")); 176 sort = new JComboBox(elements); 177 JPanel separations_pane = new JPanel(); 178 JLabel separations_label = new JLabel(get("Separations_JLabel")); 179 separations_label.setPreferredSize(LABEL_SIZE); 180 separators_preview = new JTextField(); 181 separators_preview.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false)); 182 separators_preview.setEnabled(false); // View only. 183 separators_preview.setForeground(Color.black); 184 JPanel lower_pane = new JPanel(); 185 JPanel button_pane = new JPanel(); 186 ok = new JButton(get("OK_JButton")); 187 cancel = new JButton(get("Cancel_JButton")); 188 188 // Connection 189 190 191 192 189 buttonname_label.addActionListener(new ButtonNameListener()); 190 cancel.addActionListener(new CancelListener()); 191 ok.addActionListener(new OKListener()); 192 sort_label.addActionListener(new SortListener()); 193 193 // The Toggle Button block. Done all at once so we don't end up with three for loops. 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 194 JPanel center_pane = new JPanel(); 195 center_pane.setLayout(new GridLayout(3, 9)); 196 separators = new JToggleButton[VALUES.length]; 197 SeparatorListener sl = new SeparatorListener(); 198 for(int i = 0; i < VALUES.length; i++) { 199 separators[i] = new JToggleButton(get(VALUES[i])); 200 separators[i].addActionListener(sl); 201 if(i != 0) { 202 center_pane.add(separators[i]); 203 } 204 else { 205 JLabel temp = new JLabel(get(VALUES[0])); 206 temp.setHorizontalAlignment(JLabel.CENTER); 207 center_pane.add(temp); 208 } 209 } 210 separators_preview.setText(getPreview(true)); 211 211 // Layout 212 213 214 215 212 metadata_pane.setBorder(BorderFactory.createEmptyBorder(1,0,1,0)); 213 metadata_pane.setLayout(new BorderLayout()); 214 metadata_pane.add(metadata_label, BorderLayout.WEST); 215 metadata_pane.add(metadata, BorderLayout.CENTER); 216 216 217 218 219 220 217 buttonname_pane.setBorder(BorderFactory.createEmptyBorder(1,0,1,0)); 218 buttonname_pane.setLayout(new BorderLayout()); 219 buttonname_pane.add(buttonname_label, BorderLayout.WEST); 220 buttonname_pane.add(buttonname, BorderLayout.CENTER); 221 221 222 223 224 225 222 sort_pane.setBorder(BorderFactory.createEmptyBorder(1,0,1,0)); 223 sort_pane.setLayout(new BorderLayout()); 224 sort_pane.add(sort_label, BorderLayout.WEST); 225 sort_pane.add(sort, BorderLayout.CENTER); 226 226 227 228 229 230 231 227 upper_pane.setBorder(BorderFactory.createEmptyBorder(0,0,4,0)); 228 upper_pane.setLayout(new GridLayout(3, 1)); 229 upper_pane.add(metadata_pane); 230 upper_pane.add(buttonname_pane); 231 upper_pane.add(separations_label); 232 232 233 234 235 233 separations_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createRaisedBevelBorder())); 234 separations_pane.setLayout(new BorderLayout()); 235 separations_pane.add(separators_preview, BorderLayout.CENTER); 236 236 237 238 239 237 lower_pane.setLayout(new GridLayout(2,1)); 238 lower_pane.add(separations_pane); 239 lower_pane.add(button_pane); 240 240 241 242 243 241 button_pane.setLayout(new GridLayout(1,2)); 242 button_pane.add(ok); 243 button_pane.add(cancel); 244 244 245 246 247 248 249 245 content_pane.setBorder(BorderFactory.createEmptyBorder(4,5,5,5)); 246 content_pane.setLayout(new BorderLayout()); 247 content_pane.add(upper_pane, BorderLayout.NORTH); 248 content_pane.add(center_pane, BorderLayout.CENTER); 249 content_pane.add(lower_pane, BorderLayout.SOUTH); 250 250 // Display 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 251 Dimension screen_size = Gatherer.config.screen_size; 252 controls.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2); 253 screen_size = null; 254 if(show) { 255 controls.show(); 256 // Create the new metadata, hierarchy etc. 257 if(process) { 258 process((ElementWrapper)metadata.getSelectedItem(), getPreview(false)); 259 return true; 260 } 261 return false; 262 } 263 else { 264 return true; 265 } 266 266 // We do everything -except- display the control. 267 268 269 270 271 272 273 274 275 276 277 278 267 } 268 else { 269 process = false; 270 controls.show(); 271 if(process) { 272 process((ElementWrapper)metadata.getSelectedItem(), getPreview(false)); 273 return true; 274 } 275 return false; 276 } 277 } 278 /** Determine if this classifier and another given classifier are equal. 279 279 * @param object The classifier to check against for equality, as an <strong>Object</strong>. 280 280 * @see org.greenstone.gatherer.cdm.CustomClassifier 281 281 */ 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 282 public boolean equals(Object object) { 283 if(object instanceof CustomClassifier) { 284 CustomClassifier classifier = (CustomClassifier) object; 285 if(getCommand().equalsIgnoreCase(classifier.getCommand())) { 286 return true; 287 } 288 return false; 289 } 290 else { 291 if(getCommand().equalsIgnoreCase(object.toString())) { 292 return true; 293 } 294 return false; 295 } 296 } 297 /** Method to return this pseudo-classifier represented as a String. 298 298 * @return A <strong>String</strong>. 299 299 */ 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 300 public String getCommand() { 301 StringBuffer text = new StringBuffer("classify "); 302 text.append("Hierarchy"); 303 text.append(" -metadata "); 304 text.append(hidden_mde_name); // @TODO 305 if(buttonname_label.isSelected()) { 306 text.append(" -buttonname \""); 307 text.append(buttonname.getText()); 308 text.append("\""); 309 } 310 text.append(" -hfile "); 311 text.append(hidden_mde_name + ".txt"); 312 text.append(" -hlist_at_top"); 313 text.append("\n"); 314 return text.toString(); 315 } 316 /** Retrieve the custom command, a command line that overrides and replaces some other 'actual' classifier. 317 317 * @param index The number of the classifer this one is replacing. 318 318 */ 319 320 321 322 323 324 325 326 327 328 319 public String getCustomCommand(int index) { 320 StringBuffer text = new StringBuffer("customclassifier "); 321 text.append(NAME); 322 text.append(" -replaces CL"); 323 text.append(index); 324 text.append(" -separations "); 325 text.append(getPreview(false)); 326 return text.toString(); 327 } 328 /** Get the name of this custom classifier. 329 329 * @return The name as a <strong>String</strong>. 330 330 */ 331 332 333 334 331 public String getName() { 332 return NAME; 333 } 334 /** Process a record by adding hidden metadata as necessary. 335 335 * @param record The <strong>FileNode</strong> to be edited. 336 336 * @see org.greenstone.gatherer.msm.ElementWrapper 337 337 */ 338 339 340 341 342 343 344 338 public void process(FileNode record) { 339 ElementWrapper element = (ElementWrapper) metadata.getSelectedItem(); 340 if(element != null) { 341 addMetadata(0L, record, element); 342 } 343 } 344 /** Recreate a CustomAZList given several parameters including the real classifier created during custom design. 345 345 * @param classifier The real <strong>Classifier</strong>. 346 346 * @param separations A <strong>String</strong> representing the choosen separations. … … 353 353 * @see org.greenstone.gatherer.valuetree.GValueNode 354 354 */ 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 355 public void recreate(Classifier classifier, String separations) { 356 // Rebuild controls 357 display(false); 358 // Calculate original element. 359 hidden_mde_name = classifier.getArgument("metadata").getValue(); 360 ElementWrapper hidden_mde = gatherer.c_man.getCollection().msm.getElement(hidden_mde_name); 361 String mde_name = (hidden_mde_name.substring(MetadataSetManager.HIDDEN.length() + 1)).replace('_','.'); 362 ElementWrapper mde = gatherer.c_man.getCollection().msm.getElement(mde_name); 363 // Set metadata element combobox. 364 metadata.setSelectedItem(mde); 365 // Set button name. 366 String bn = classifier.getArgument("buttonname").getValue(); 367 if(bn != null) { 368 buttonname_label.setSelected(true); 369 buttonname.setBackground(Color.white); 370 buttonname.setEnabled(true); 371 buttonname.setText(bn); 372 } 373 // Set sort element. 374 String sort_mde_name = classifier.getArgument("sort").getValue(); 375 ElementWrapper sort_mde = gatherer.c_man.getCollection().msm.getElement(sort_mde_name); 376 if(sort_mde != null) { 377 sort_label.setSelected(true); 378 sort.setBackground(Color.white); 379 sort.setEnabled(true); 380 sort.setSelectedItem(sort_mde); 381 } 382 // Recover value tree. 383 GValueModel model = gatherer.c_man.getCollection().msm.getValueTree(hidden_mde); 384 // For each token in the tokenizer, set toggle buttons and recover node. 385 StringTokenizer tokenizer = new StringTokenizer(separations, ","); 386 mappings = new Hashtable(); 387 while(tokenizer.hasMoreTokens()) { 388 String key = tokenizer.nextToken(); 389 for(int j = 1; j < STRING_VALUES.length; j++) { 390 if(key.startsWith(STRING_VALUES[0])) { 391 j = STRING_VALUES.length; 392 } 393 else if(key.startsWith(STRING_VALUES[j])) { 394 separators[j].setSelected(true); 395 j = STRING_VALUES.length; 396 } 397 } 398 398 // Rebuild mappings hashtable for this pattern. Add it if not present. 399 399 GValueNode node = model.addValue(key); 400 400 // If the key is simple, ie "C", then add the mapping "C"->node 401 402 403 404 405 406 401 if(node == null) { 402 // Do nothing. 403 } 404 else if(key.indexOf("-") == -1) { 405 mappings.put(key, node); 406 } 407 407 // If the key is more complex, say "D-L", then we add mappings for all string values so "D"->node, "E"->node, ... "L"->node. This is miles eaiser to do here, than when you are trying to match a records metadata ie matchin "D-L" to "Igloos are cool". Note that it is guarantee that the keys are all of the same length, ie "A-L", "MA-ML", "MMA-STF", "STFA-ZZZZ". 408 409 410 411 412 413 414 415 416 417 418 419 408 else { 409 String start = key.substring(0, key.indexOf("-")); 410 String end = key.substring(key.indexOf("-") + 1); 411 for(key = start; key != null && key.compareTo(end) <= 0; key = increment(key)) { 412 ///ystem.err.println("Adding " + key + " -> " + node); 413 mappings.put(key, node); 414 } 415 } 416 } 417 separators_preview.setText(getPreview(true)); 418 } 419 /** Sets the value of Gatherer, for those classes loaded dynamically. 420 420 * @param gatherer A reference to the <strong>Gatherer</strong>. 421 421 */ 422 423 424 422 public void setGatherer(Gatherer gatherer) { 423 this.gatherer = gatherer; 424 } 425 425 426 427 426 public void setManager(ClassifierManager manager) { 427 } 428 428 429 429 /** Translate this object into a string such as you would find in the collection configuration file. 430 430 * @return A <strong>String</strong> representation. 431 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 462 463 464 465 466 467 468 432 public String toString() { 433 StringBuffer text = new StringBuffer("classify "); 434 text.append(NAME); 435 text.append(" -metadata "); 436 text.append(metadata.getSelectedItem().toString()); 437 if(buttonname_label.isSelected()) { 438 text.append(" -buttonname \""); 439 text.append(buttonname.getText()); 440 text.append("\""); 441 } 442 text.append(" -separations "); 443 text.append(getPreview(false)); 444 return text.toString(); 445 } 446 /** Add a pertinant piece of metadata to the given record. */ 447 private void addMetadata(long id, FileNode record, ElementWrapper element) { 448 // Add custom metadata based on target metadata. No recursion. 449 ArrayList temp_value = Gatherer.c_man.getCollection().gdm.getMetadata(record.getFile(), element); 450 boolean found = false; // Only want to add the custom classifier metadata once. 451 for(int i = 0; !found && i < temp_value.size(); i++) { 452 String metadata_value = (String)temp_value.get(i); 453 for(Enumeration keys = mappings.keys(); metadata_value != null && keys.hasMoreElements(); ) { 454 String key = (String)keys.nextElement(); 455 // Try to match the value and the pattern. Remember to check for any case, ie key is '#' and metadata_value starts with anything other than a character. 456 if(metadata_value.toUpperCase().startsWith(key) || (key.equals("#") && !Character.isLetter(metadata_value.charAt(0)))) { 457 GValueNode node = (GValueNode) mappings.get(key); 458 if(node != null) { // And it shouldn't. 459 Metadata metadata = new Metadata(node); 460 //record.addMetadata(id, metadata, MetaEditPromptBox.ACCUMULATE_ALL, false, 1); 461 Gatherer.c_man.getCollection().msm.fireMetadataChanged(0, record, null, metadata); 462 found = true; 463 } 464 } 465 } 466 } 467 } 468 /** Create a separation preview String from the currently selected toggle buttons. 469 469 * @param spaces <i>true</i> if the returned String should contain spaces for readability, <i>false</i> if we mean to process it and spaces would just make that more difficult. 470 470 * @return A <strong>String</strong> representing the current separation state, such as "#, A-L, M-Z". 471 471 */ 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 472 private String getPreview(boolean spaces) { 473 String sep_sep = ","; 474 if(spaces) { 475 sep_sep = ", "; 476 } 477 StringBuffer preview = new StringBuffer(get(VALUES[0])); 478 for(int i = 1; i < separators.length - 1; i++) { 479 if(separators[i].isSelected()) { 480 // Special case, where we specifically avoid #-#, A... 481 if(i == 1) { 482 preview.append(sep_sep); 483 preview.append(get(VALUES[i])); 484 } 485 // Check previous value. We don't want ...A-L, M-M, N... 486 else if(separators[i - 1].isSelected()) { 487 preview.append(sep_sep); 488 preview.append(get(VALUES[i])); 489 } 490 // Otherwise ..-VALUE[i-1], VALUE[i]... 491 else { 492 preview.append("-"); 493 preview.append(get(VALUES[i-1])); 494 preview.append(sep_sep); 495 preview.append(get(VALUES[i])); 496 } 497 } 498 } 499 // Special case of "...-Y,Z" 500 if(separators[separators.length - 1].isSelected()) { 501 preview.append("-"); 502 preview.append(get(VALUES[VALUES.length - 2])); 503 preview.append(sep_sep); 504 preview.append(get(VALUES[VALUES.length - 1])); 505 } 506 // Otherwise "...-Z" 507 else { 508 preview.append("-"); 509 preview.append(get(VALUES[VALUES.length - 1])); 510 } 511 return preview.toString(); 512 } 513 /** Load the custom argument dictionary if necessary, then retrieve the requested phrase. 514 514 * @param key A key <strong>String</strong> which maps to the phrase to retrieve. 515 515 * @return A phrase as a <strong>String</strong>. … … 517 517 * @see org.greenstone.gatherer.Gatherer 518 518 */ 519 520 521 522 523 524 525 526 527 528 529 519 private String get(String key) { 520 if(dictionary == null) { 521 dictionary = ResourceBundle.getBundle("org.greenstone.gatherer.cdm.custom." + NAME, Gatherer.config.getLocale("general.locale", false)); 522 } 523 return dictionary.getString(key); 524 } 525 /** Listens to the buttonname checkbox, and enable buttonname appropriately when action detected. */ 526 private class ButtonNameListener 527 implements ActionListener { 528 /** When an action is performed on a registered control, this method is called which either enables or disables the buttonname field depending on the buttonname checkbox. 529 * @param event An <strong>ActionEvent</strong> containing information about the action performed. 530 530 */ 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 531 public void actionPerformed(ActionEvent event) { 532 if(buttonname_label.isSelected()) { 533 buttonname.setBackground(Color.white); 534 buttonname.setEnabled(true); 535 } 536 else { 537 buttonname.setBackground(Color.lightGray); 538 buttonname.setEnabled(false); 539 } 540 } 541 } 542 /** Listens to the cancel button, and disposes appropriately when action detected. */ 543 private class CancelListener 544 implements ActionListener { 545 /** If the cancel button is pressed then we should dispose of the dialog without processing any records. 546 * @param event An <strong>ActionEvent</strong> containing information about the action performed. 547 547 */ 548 549 550 551 552 553 554 555 556 557 548 public void actionPerformed(ActionEvent event) { 549 process = false; 550 controls.dispose(); 551 } 552 } 553 /** Listens to the ok button, and sets process to true then disposes appropriately when action detected. */ 554 private class OKListener 555 implements ActionListener { 556 /** If the ok button is pressed then we should dispose of the dialog after processing all records. 557 * @param event An <strong>ActionEvent</strong> containing information about the action performed. 558 558 */ 559 560 561 562 563 564 565 566 567 568 559 public void actionPerformed(ActionEvent event) { 560 process = true; 561 controls.dispose(); 562 } 563 } 564 /** Listens for the toggling of a separator value, and updates the separator preview field. */ 565 private class SeparatorListener 566 implements ActionListener { 567 /** When one of the separator buttons is toggled we update the separator preview field. 568 * @param event An <strong>ActionEvent</strong> containing information about the action performed. 569 569 */ 570 571 572 573 574 575 576 577 578 570 public void actionPerformed(ActionEvent event) { 571 separators_preview.setText(getPreview(true)); 572 } 573 } 574 /** Listens to the sort checkbox, and enables/disables sort appropriately when action detected. */ 575 private class SortListener 576 implements ActionListener { 577 /** If this checkbox is actioned, enabled or disable the sort control based on whether we are checked (selected) or not. 578 * @param event An <strong>ActionEvent</strong> containing information about the action performed. 579 579 */ 580 581 582 583 584 585 586 587 588 589 590 591 580 public void actionPerformed(ActionEvent event) { 581 if(sort_label.isSelected()) { 582 sort.setBackground(Color.white); 583 sort.setEnabled(true); 584 } 585 else { 586 sort.setBackground(Color.lightGray); 587 sort.setEnabled(false); 588 } 589 } 590 } 591 /** Display a progress bar while creating the required hidden system hierarchy. 592 592 * @param element An <strong>ElementWrapper</strong> containing the metadata element we want to build a custom classifier on. 593 593 * @param state A <strong>String</strong> representing the currently selected separators, of the form "#,A-L,MA-Ml,MM-MZ,N-Z". */ 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 594 private void process(ElementWrapper element, String state) { 595 // Create a new progress bar dialog, using these divisions: 596 // 33% - Creation and removal of old metadata tree. 597 // 33% - Creation of new metadata tree, 33 / <number of separations>. 598 // 33% - Allocation of metadata to records, 33 / <number of files>. 599 // Hopefully the previous dialog should have already vanished (its dispose() caused by the process click). 600 ProgressDialog pd = new ProgressDialog("Custom Classifier Creation", "Preparing for operation."); 601 // Step 1: Create the new dummy element and add it if necessary. 602 pd.setText("Creating dummy metadata element."); 603 MetadataSet hidden_mds = gatherer.c_man.getCollection().msm.getSet(MetadataSetManager.HIDDEN); 604 Element hidden_e = hidden_mds.getElement(element.toString().replace('.','_')); 605 boolean found = true; 606 ElementWrapper hidden_mde = null; 607 if(hidden_mde != null) { 608 hidden_mde = new ElementWrapper(hidden_e); 609 } 610 else { 611 hidden_mde = hidden_mds.addElement(element.toString().replace('.','_')); 612 found = false; 613 } 614 hidden_mde_name = hidden_mde.toString(); 615 pd.increase(1,2,20); 616 // Step 2: Remove any existing value tree for this element. Wastefull I know but I don't want to lag for too long, and this is the quickest way. 617 pd.setText("Removing any existing hierarchy."); 618 if(found) { 619 hidden_mds.removeValueTree(hidden_mde); 620 } 621 pd.increase(1,2,20); 622 // Step 3: Create a value tree for this element. 623 pd.setText("Creating new hierary root."); 624 GValueModel value_tree = gatherer.c_man.getCollection().msm.getValueTree(hidden_mde); 625 pd.increase(5, 5, 5); 626 // Step 4: Build the single level value hierarchy using state's value. Here a hashtable mapping string patterns to value nodes is built. 627 pd.setText("Creating separations."); 628 StringTokenizer tokenizer = new StringTokenizer(state, ","); 629 int separator_count = tokenizer.countTokens(); 630 mappings = new Hashtable(); 631 for(int i = 0; i < separator_count; i++) { 632 String key = tokenizer.nextToken(); 633 GValueNode node = value_tree.addValue(key); 634 634 // If the key is simple, ie "C", then add the mapping "C"->node 635 636 637 635 if(key.indexOf("-") == -1) { 636 mappings.put(key, node); 637 } 638 638 // If the key is more complex, say "D-L", then we add mappings for all string values so "D"->node, "E"->node, ... "L"->node. This is miles eaiser to do here, than when you are trying to match a records metadata ie matchin "D-L" to "Igloos are cool". Note that it is guarantee that the keys are all of the same length, ie "A-L", "MA-ML", "MMA-STF", "STFA-ZZZZ". 639 640 641 642 643 644 645 639 else { 640 String start = key.substring(0, key.indexOf("-")); 641 String end = key.substring(key.indexOf("-") + 1); 642 for(key = start; key != null && key.compareTo(end) <= 0; key = increment(key)) { 643 mappings.put(key, node); 644 } 645 } 646 646 // Each iteration. 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 647 pd.increase(1, separator_count, 25); 648 } 649 // Step 5: Recurse the entire tree, adding the appropriate values where necessary (overwriting any existing value for this element). 650 pd.setText("Allocating metadata to records."); 651 int document_count = gatherer.c_man.getCollection().getDocumentCount(); 652 TreeModel record_tree = gatherer.c_man.getRecordSet(); 653 FileNode records[] = ArrayTools.add(null, (FileNode)record_tree.getRoot()); 654 while(records != null) { 655 if(records[0].isLeaf()) { 656 addMetadata(0L, records[0], element); 657 // Each iteration. 658 pd.increase(1, document_count, 50); 659 } 660 else { 661 // Add all children to records at once hopefully. 662 FileNode children[] = new FileNode[records[0].getChildCount()]; 663 for(int i = 0; i < children.length; i++) { 664 children[i] = (FileNode) records[0].getChildAt(i); 665 } 666 records = ArrayTools.add(records, children); 667 } 668 records = ArrayTools.tail(records); 669 } 670 // Step 6: Done. 671 pd.dispose(); 672 } 673 /** A dialog window used to show the progress of processing the file records in terms of adding hidden metadata. */ 674 private class ProgressDialog 675 extends JDialog { 676 /** The current value represented by the progress bar (where value is double and the progress bar shows an int). */ 677 private double value = 0.0; 678 /** The default size of this dialog. */ 679 private Dimension dialog_size = new Dimension(500,100); 680 /** The label explaining what action is currently happening (1 of 5 steps). */ 681 private JLabel label = new JLabel(); 682 /** The progress bar itself. */ 683 private JProgressBar bar = new JProgressBar(); 684 /** Constructor. 685 * @param t The title for this dialog as a <strong>String</strong>. 686 * @param l The initial label for the progress bar also a <strong>String</strong>. 687 */ 688 public ProgressDialog(String t, String l) { 689 super(); 690 setModal(false); 691 setSize(dialog_size); 692 setTitle(t); 693 693 // Create 694 695 696 697 698 694 JPanel content_pane = (JPanel) getContentPane(); 695 label.setText(l); 696 bar.setMaximum(100); 697 bar.setMinimum(0); 698 bar.setValue(0); 699 699 // Connect 700 700 // Layout 701 702 703 704 701 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 702 content_pane.setLayout(new BorderLayout()); 703 content_pane.add(label, BorderLayout.NORTH); 704 content_pane.add(bar, BorderLayout.CENTER); 705 705 // Display 706 707 708 709 710 711 706 Dimension screen_size = Gatherer.config.screen_size; 707 setLocation((screen_size.width - dialog_size.width) / 2, (screen_size.height - dialog_size.height) / 2); 708 screen_size = null; 709 show(); 710 } 711 /** Increase the progress bar by a certain ammount. 712 712 * @param item An <i>int</i> indicating what item number this is. 713 713 * @param out_of An <i>int</i> detailing the number of items expected in total for this phase. 714 714 * @param total The maximum value of the progress bar as an <i>int</i>. 715 715 */ 716 717 718 716 public void increase(int item, int out_of, int total) { 717 value = value + (((double) item / (double) out_of) * (double)total); 718 int int_value = (int) value; 719 719 ///ystem.err.println("Value is " + value + " which rounds to " + int_value); 720 721 722 723 724 720 if(int_value != bar.getValue()) { 721 bar.setValue(int_value); 722 } 723 } 724 /** Set the message shown in the progress bar. 725 725 * @param l The new progress bar label as a <strong>String</strong>. 726 726 */ 727 728 729 730 731 727 public void setText(String l) { 728 label.setText(l); 729 } 730 } 731 /** The String equivelent of int++, this method increments the value of a String by one letter at a time. 732 732 * @param str The <strong>String</strong> to be incremented. 733 733 * @return A <strong>String</strong> whose 'checksum' value (adding the INT_VALUE[] of the letters together) is one greater than the initial String, while still containing only those values in STRING_VALUE[]. 734 734 */ 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 735 public String increment(String str) { 736 ///ystem.err.print("Incrementing " + str + " -> "); 737 char chars[] = str.toCharArray(); 738 boolean found = false; 739 int pos = str.length() - 1; 740 while(found == false && pos >= 0) { 741 if((int)chars[pos] + 1 <= INT_VALUES[26]) { 742 if((int)chars[pos] == INT_VALUES[0]) { // Anything else symbol 743 chars[pos] = (char) INT_VALUES[1]; 744 } 745 else { 746 chars[pos] = (char)((int)chars[pos] + 1); 747 } 748 found = true; 749 } 750 else { 751 chars[pos] = (char)INT_VALUES[1]; 752 pos--; 753 } 754 } 755 // If we haven't found it yet, return null. 756 if(!found) { 757 return null; 758 } 759 ///ystem.err.println(String.valueOf(chars)); 760 return String.valueOf(chars); 761 } 762 762 } 763 763
Note:
See TracChangeset
for help on using the changeset viewer.