====== Trees mit RDF ====== Mit Xul können Trees erstellt werden. Diese können mit verschiedenen Datasourcen gefüttert werden. (XML, RDF, etc) Hier ein Beispiel wie ein Tree mit RDF als Datenquelle definiert wird: So siehts aus: {{:wiki:xul:tree.png|}} [[xul_trees_fehlersuche|Hier]] einige Tipps falls der Tree keine Daten anzeigt. ====== Aktualisieren des Trees ====== Zum Aktualisieren der Daten setzen wir die Datasource einfach neu. Um das Caching von RDFs zu verhindern, hänge ich an die URL einen aktuellen Timestamp an: function gettimestamp() { var now = new Date(); var ret = now.getHours()*60*60*60; ret = ret + now.getMinutes()*60*60; ret = ret + now.getSeconds()*60; ret = ret + now.getMilliseconds(); return ret; } function refreshTree() { document.getElementById("kontakt-adressen-tree").setAttribute("datasource","http://www.oesi.org/xul/rdf/adresse.rdf.php"+gettimestamp()); } Diese Methode bringt allerdings folgende Probleme mit sich: - da die Daten asynchron in den Tree geladen werden weiss ich nicht ab wann alle Daten geladen wurden - bei zunehmender Datenmenge dauert die Aktualisierung relativ lange - Fehler beim Laden können nicht abgefangen werden Um diese Probleme zu umgehen, sind einige Änderungen erforderlich. An die Datasource wird zusätzlich ein XMLSinkObserver angehängt. Dieser informiert uns wenn die Daten fertig geladen wurden. Zusätzlich hängen wir noch einen Listener an den Tree. Von diesem werden wir dann darüber informiert, wenn die Daten im Tree aktualisiert wurden. var KontaktAdressenTreeSinkObserver = { onBeginLoad : function(pSink) {}, onInterrupt : function(pSink) {}, onResume : function(pSink) {}, onError : function(pSink, pStatus, pError) { alert('Fehler beim Laden der Daten '+pError); }, onEndLoad : function(pSink) { //wenn die Daten in der Datasource aktualisiert wurden, kann der Tree neu aufgebaut werden //dies erledigt die Funtkion rebuild() für uns: netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); document.getElementById('kontakt-adressen-tree').builder.rebuild(); } }; var KontaktAdressenTreeListener = { willRebuild : function(builder) { }, didRebuild : function(builder) { //die aktualisierung des Trees ist nun abgeschlossen. //ab nun koennen per Script wieder Eintraege markiert werden etc. alert('Die Daten sind jetzt auf dem neuesten Stand'); } }; var AdressenTreeDatasource; onLoad() { url = "http://www.oesi.org/xul/rdf/adresse.rdf.php"; //Tree Element holen var treeAdressen=document.getElementById('kontakt-adressen-tree'); var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService); //Datasource holen AdressenTreeDatasource = rdfService.GetDataSource(url); AdressenTreeDatasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource); AdressenTreeDatasource.QueryInterface(Components.interfaces.nsIRDFXMLSink); //Datasource an den Tree haengen treeAdressen.database.AddDataSource(AdressenTreeDatasource); //Observer an die Datasource haengen AdressenTreeDatasource.addXMLSinkObserver(KontaktAdressenTreeSinkObserver); //Listener an den Tree haengen treeAdressen.builder.addListener(KontaktAdressenTreeListener); } function refreshTree() { //Aktualisieren des Trees AdressenTreeDatasource.Refresh(false); } Diese Methode ist zwar etwas aufwendiger als die vorhergehende, dafür ist aber gesichert, dass die Daten vollständig geladen wurden. Wenn die RDF URL zur Laufzeit verändert werden muss (unterschiedliche Parameter zB für Adressen einer anderen Person) ist zu beachten, dass die "alten" Listener und Datasources vorher vom Tree entfernt werden. //Listener und Observer entfernen try { AdressenTreeDatasource.removeXMLSinkObserver(KontaktAdressenTreeSinkObserver); treeAdressen.builder.removeListener(KontaktAdressenTreeListener); } catch(e) {} //Alte Datasource entfernen var oldDatasources = treeAdressen.database.GetDataSources(); while(oldDatasources.hasMoreElements()) { treeAdressen.database.RemoveDataSource(oldDatasources.getNext()); } Wenn die URL geändert wird, sollte auf jeden Fall ein timestamp an die URL angehängt werden. Geschieht dies nicht, kann es vorkommen, dass das RDF bereits im Cache vorhanden ist und nicht wirklich neu geladen wird. In diesem Fall wird der SinkObserver nicht ausgelöst und infolgedessen der Tree auch nicht refresht! ====== Einträge im Tree markieren ====== Da nach dem Refresh eines Trees die vorher markierte Zeile nicht automatisch markiert wird, muss dies vom Programm selbst erledigt werden. Dazu holen wir vor dem Refresh die aktuell markierte Zeile: var tree = document.getElementById('adressen-tree'); var col = tree.columns ? tree.columns["adresse-treecol-adresse_id"] : "adresse-treecol-adresse_id"; try { SelectedID=tree.view.getCellText(tree.currentIndex,col); } catch(e) { SelectedID=null; } AdressenTreeDatasource.Refresh(false); Nachdem der Tree Refresht wurde (didRebuild) selectieren wir die Zeile neu function TreeSelectEntry() { var tree=document.getElementById('adressen-tree'); var items = tree.view.rowCount; //Anzahl der Zeilen ermitteln //In der globalen Variable ist der zu selektierende Eintrag gespeichert if(SelectedID!=null) { for(var i=0;i