Editing the model

So a phenote.edit.CharChangeEvent has a phenote.edit.TransactionI.
so when a gui component like CharFieldGui wants to edit the model  it calls a method on the EditManager. For instance, for updating multiple fields at once CharFieldGui makes a bunch of UpdateTransactions adds them to a CompoundTransaction and sends the CompoundTransaction to EditManager.updateModel(). updateModel calls editModel() on the CompoundTransaction (which actually edits the model), make a CharChangeEvent with the transaction and sends out the CharChangeEvent out to CharChangeListeners notifying them that the model has been changed, and adds the transaction to its list of transactions (for undo).
A phenote.edit.TransactionI knows how to edit and undo its edit to the datamodel.

Adding new configuration params

Phenote configuration is done with a xml file, that xml file is read & written with apaches xml beans. Xml beans code generates java classes from an xsd file.

1) Add your new config item to the config/phenote-config.rnc file. An rnc file is (i think) a handier way of specifying xml schemas. The best thing to do there is to look how other elements are configured and just copy & tweek.

2) trang the rnc file into an xsd file.
2a) To do this you first need to download the trang jar file see: http://www.thaiopensource.com/relaxng/trang.html and its download dir http://www.thaiopensource.com/download/ where you can download a zip file like trang-20030619.zip
and unzip which should give you the jar - and put that jar whereever you like.
2b) cd to conf directory and run trang with rnc as input and xsd as output like so and this will recreate the xsd:
java -jar /path/to/trang/trang.jar phenote-config.rnc phenote-config.xsd
You can check the xsd to see if it has the element that you added in the rnc if you like.

3) generate xmlbeans from xsd.
3a) You need to download scomp, and jsr-api.jar and xbean.jar jar files from apache xml beans
see http://xmlbeans.apache.org/ and its download dir http://www.apache.org/dyn/closer.cgi/xmlbeans
current tgz or zip - and unzip and/or untar it. The relevant bits are bin/scomp and the jsrwithnumbers.jar and xbean.jar
make sure to change the permissions on scomp so its executable.
3b) Before we run scomp we need to set envrionment vars something like so (for unix/linux at least):
export XMLBEANS_HOME=/home/me/xmlbeans-2.1.0
export PATH=$PATH:$XMLBEANS_HOME/bin
export CLASSPATH=$XMLBEANS_HOME/lib/xbean.jar:$XMLBEANS_HOME/lib/jsr173_1.0_api.jar:$CLASSPATH
3c) Then run scomp using the above jars and the xsd file to create jars/phenote (all on one line):

scomp -out /path/to/phenote/jars/phenoteconfigbeans.jar /home/mgibson/p/conf/phenote-config.xsd

Now you should have a phenoteconfigbeans.jar file. With this jar we can now write java config code.

4) Modify java config files. Go to the file src/java/phenote/config/Config.java.

a) First put in the appropriate import statement from the xmlbean jar, something like
import phenote.config.xml.TermHistoryDocument.TermHistory;

b) The simple case is just adding a top level config boolean option - like enabling term history - so ill go with that.
- the new parameter would automatically be read into an xml bean - write a private getter for the new bean value like so (putting in default value if null)
  private TermHistory getHistoryBean() {
    TermHistory history = phenoConfigBean.getTermHistory();
    if (history == null) {
      history = phenoConfigBean.addNewTermHistory();
      history.setEnable(false); // default false
    }
    return history;
  }
 
- add a public getter method like:
  public boolean termHistoryIsEnabled() {
    return getHistoryBean().getEnable();
  }

- setters are used by merge code and will be used in future by gui config:
  public void setTermHistory(boolean setter) {
    getHistoryBean().setEnable(setter);
  }

- you need to deal with config upgrades to make sure youre new param gets merged into old configs without wiping out a user previous config settings (the default and -u option run by webstart)
if you dont want the master/template config file to alter the value of a users local config then nothing needs to be done here. but if you do then...
so in this method:

void mergeNewWithOld(URL newConfig,File oldDotConfFile)

where you need to add something like

    oldCfg.setAutoUpdate(newCfg.autoUpdateIsEnabled());

notice this just wipes out the new with the old - you may actually want to ask the user if they want this to happen (with a popup box or something) - this example is for auto update.

Source for generate xml beans:
It can be handy to look at the actual source of the xmlbeans created by scomp, and scomp has such an option:
instead of the -out used above, use -src, and tell scomp where you would like the source plopped:
scomp -src ~/phenote/config-xmlbeans-src /home/mgibson/p/conf/phenote-config.xsd

Datamodel
Each row is represented by a phenote.datamodel.CharacterI interface, the implementation of which is phenote.datamodel.Character. The whole table is just a list of Characters: CharacterList. phenote.dataadapter.CharacterListManager manages the CharacterLists for each table (groups of fields spurn separate tables), and sends out CharChangeEvents when a new CharacterList is loaded.
A Character is actually rather generic. Its really just a hash with CharField keys and CharFieldValue values. So a CharField represents a whole column/field of the table (eg Quality) and CharFieldValue represent a cell - a column/field of a row.

So what happens to a field from config to datamodel to gui?
So I dont know if this is the best way to explain this but what the heck. So the fields in the rnc as explained above get tranged into xsd and then scomped (code generated) into java xml beans. phenote.config.Config makes the call to parse the config xml file into xml bean objects. One field xml bean object is created for each field in the config file. Config wraps the field xml bean with the FieldConfig object (just for convenience - may want to strip out FieldConfig at some point?). The OntologyDataAdapter iterates through FieldConfig objects and creates a CharField for each one. A CharField is a datmodel object that represents a column of the table basically (a field - see above).