31.05.2010 =========== 12 Uhr: Kontextsensitive Comboboxen sind noch immer nicht fertig. Ich schreib mir jetzt mal auf, woran ich da schon seit Tagen frickle. Im folgenden rede ich von `country` und `city`, weil das mein Testbeispiel ist. Ich rede aber natürlich vom Prinzip, nicht von diesem einen Fall. `country` ist die "context source" und `city` das "context target". Im change-Event des country-Feldes wird der Kontext von city jetzt gesetzt. Das geht. Aber das reicht nicht: z.B. ist der Kontext von city noch falsch, wenn man country vorher gar nicht bearbeitet hat, oder wenn man es auf einem anderen Record bearbeitet hat. Wenn ich setContextValue() für city im focus-Event von city aufrufe: das geht fast immer, aber nicht in der Grid. Dort ist ja nur ein country-Feld für alle Records, und das wird nur gesetzt, wenn man drauf klickt. Am logischsten scheint mir, setContextValue (außer im change-Event) auch in `load_master_record()` zu rufen. Hierbei ist das Problem aber, dass der Wert von country (die Id des Landes) nicht in `record.data.country` sondern in `record.data.countryHidden` sitzt, weil country eine Combobox ist. Aber ein Chooser weiß das nicht, er hat nicht zu wissen, was die Context sources für Felder sind. Deshalb ruft er den Wert mit `getValue()` aus dem country-Feld. Das setzt freilich voraus, dass das Source-Feld immer im Formular enthalten ist; ein bisschen einschränkend, aber damit könnten wir leben. (Falsch: alles in diesem Absatz ist Quatsch; siehe später.) Das funktioniert jetzt theoretisch für alle lokalen Comboboxen. Aber in Lino sind die meisten Comboboxen remote, d.h. deren `setValue()` (das von `BasicForm.loadRecord()` gerufen wird) ist verzögert: es macht erst noch eine weiteren AJAX-Aufruf, um den Store der Combobox zu laden. Eine Combobox braucht ja nicht nur ihren Wert, sondern auch den dazugehörigen Text (z.B. Text "Belgien" für den Wert "BE"). Deshalb kriegt das City-Feld, wenn es gleich nach BasicForm.loadRecord() das Country-Feld nach seiner value fragt, als Antwort "leer". Puh! Zwei Fliegen mit einer Klappe hätten wir, wenn ich mein ComboBox.setValue() dahingehend ändere, dass dieser zusätzliche AJAX-Aufruf gar nicht mehr nötig ist. Den zur Value zugehörigen Text haben wir nämlich schon vom Server bekommen, der ist im Record gespeichert. Deshalb folgender neuer Code in der lino.js:: Ext.override(Ext.form.BasicForm,{ loadRecord : function(record){ var field, id; for(id in record.data){ if(!Ext.isFunction(record.data[id]) && (field = this.findField(id))){ field.setValue(record.data[id],record); if(this.trackResetOnLoad){ field.originalValue = field.getValue(); } } } return this; }, }); Meine `loadRecord` recht also im Gegensatz zur Originalversion jedem Feld nicht nur `setValue()` den rohen Wert, sondern als zweiten Parameter auch den ganzen Record. (Dass mein `loadRecord()` nur noch hashed arrays verträgt, liegt nur daran, dass dieser Fall so weit ich sehen kann von Lino nie benutzt werden wird.) Und in meiner `Combobox.setValue()` steht dann ganz einfach:: } else if (record != undefined) { text = record.data[this.name]; //~ console.log(this.name,'.setValue',v,'got text ',this.name,' from record ',record); } else { Und vorbei ist es mit den unnützen AJAX beim Anzeigen von Comboboxen in Detail-Fenster! Schön. Eins fehlt noch: in der Grid wird der Kontext noch nicht gesetzt. Am besten müsste ich hier aufs rowselected-Event horchen. Nein, Quatsch, das gibt es gar nicht. Das beforeedit-Event brauch ich. Das geht gut, aber... in einer Grid wird logischerweise immer nur der Editor gefüllt, der gerade bearbeitet werden soll. Und mein before_row_edit ruft ja `country_field.get_value` ab, wenn city_field bearbeitet wird. Da ist im Falle einer Grid nichts zu holen. Lösung? Der Chooser sollte also doch irgendwie wissen, ob die source fields Comboboxen sind, und mein before_row_edit-Event holt die Werte direkt aus dem Record. Deswegen in `ext_windows.MasterWrapper.js_render()` ein kleiner Test:: if isinstance(f,models.ForeignKey) or (isinstance(f,models.Field) and f.choices): fname = f.name+ext_requests.CHOICES_HIDDEN_SUFFIX else: fname = f.name before_row_edit.append("%s.setContextValue(%r,record.data[%r]);" % ( e.ext_name,f.name,fname)) Das ist nicht wirklich elegant, aber es funktioniert. Super! **Also hier die frohe Mitteilung des Tages: Kontextsensitive Comboboxen funktionieren wieder!** Und zwar besser denn je: auch für ungespeicherte Records, und auch für normale Textfelder mit `choices`. [http://code.google.com/p/lino/source/detail?r=4aebca79aedd4fd2f4d0671ef5e7d729cacc4097 Check-In]. Als nächstes # müsste jetzt die Konfigurierung der Dokumentvorlagen für Notizen machbar sein, # und dann will ich auch mal den fensterlosen Weg probieren. Macht es Sinn, im Browser eine Desktop-Anwendung imitieren zu wollen? Sind die Unterfenster in Lino der falsche Weg? Wenn ich z.B. in [http://www.insideria.com/2009/09/50-most-usable-rias.html 50 Most Usable RIAs] lese, dann sehe ich da keine Anwendung, die mit Fenstern arbeitet.