Entwicklung grafischer Anwendungen mit Mozilla XUL und XULRunner

Jan Sören Ramm

Style Sheets, Lokalisierung und Aktionen:


Style Sheets

Wozu Style Sheets?

Wie aus HTML bekannt, ist das Ziel vom Einsetzen von Style Sheets das Layout und Design zu trennen. Des weiteren können unterschiedliche Darstellungsformen für unterschiedliche Medien definiert werden, damit eine Anwendung auf PDA's oder Druckern anders dargestellt wird als auf einem PC.

Wie werden Style Sheets verwendet?

Es gibt drei Möglichkeiten ein Style Sheet einzubinden, als externe Datei (empfohlen), als Inline-Styleinformationen und im Style-Attribut des jeweiligen Elementes. Im weiteren wird lediglich auf das Einbinden einer externen Style Sheet Datei eingegangen, da dies auch die von Mozilla empfohlene Variante ist.
Mit Hilfe des "xml-stylesheet" Tag wird auf eine externe CSS-Datei verwiesen, welche die Styleinformationen enthält;

example2.xul

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="main.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <label control="myInput" value="Html-Quelltext:"/>
  <textbox id="myInput" multiline="true" cols="40" rows="2" value=""/>
  <button id="submitButton" label="Speichern"/>
</window>

In Zeile 3 wird die CSS-Datei geladen.

main.css
window{
  background-color:white;
}
#submitButton{
  color:red;
}

In der "main.css" wird die Hintergrundfarbe des Fensters auf weiß gesetzt, sowie der Text auf des Buttons rot eingefärbt.

ohne Style Sheet

ohne Style Sheet

mit Style Sheet

mit Style Sheet


Lokalisierung

Unter Lokalisierung wird allgemein die Übersetzung von Strings verstanden. Diese Methode wird z.B. zum Übersetzen von Menü-Beschriftungen verwendet. Bei größeren Texten, die auch Variablen beinhalten, sollten Templates verwendet werden um auf die unterschiedlichen Satzbauten der verschiedenen Sprachen eingehen zu können.

Wozu Lokalisierung?

Lokalisierung ist ein relativ geringer Aufwand und stellt die Möglichkeit das Programm später einmal zu Übersetzen bereit. Diese Übersetzung kann dann auch von Nicht-Programmierern vorgenommen werden, da die Strukturen einer Lokalisierungsdatei sehr einfach gehalten sind.

Wie werden Lokalisierungen vorgenommen?

Zuerst sollten in den XUL-Dateien die statischen Strings durch Entity-Referenzen ersetzt werden. Anschließend muss eine Lokalisierungsdatei (.DTD) erzeugt werden und die Entitäten eintragen werden. Zum Abschluss muss die Lokalisierungsdatei in die XUL-Datei eingebunden werden.

XUL-Datei - example3.xul

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="main.css" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://example3/locale/example3.dtd">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <label control="myInput" value="&htmlQuelltext;"/>
  <textbox id="myInput" multiline="true" cols="40" rows="2" value=""/>
  <button id="submitButton" label="&save;"/>
</window>

In Zeile 4 wird die Lokalisierungsdatei eingebunden und in Zeile 6 und 8 wird die entsprechende Entity-Referenz eingetragen.

Lokalisierungsdatei - example3.dtd

<!ENTITY htmlQuelltext "HTML-Quelltext">
<!ENTITY save "Speichern">

Aktionen

Eventlistner

Jedem XUL-Element können beliebig viele Eventlistener hinzugeügt werden. Es existieren alle bereits aus Javascript bekannten Eventlistner wie: click, blur etc..
Zusätzlich ist noch der Eventlistener command hinzugekommen, welcher für jedes Element auf die "Standard-Aktion" wartet z.B. beim Button auf das Click-Event.

Beispiel um mit dem onCommand-Attribut auf einem Button eine MessageBox auszugeben

					...
					<button label="Speichern" oncommand="alert('hallo');" />
					...
				
Alternative mit EventBinding über Javascript
XUL-Datei mit Button-ID und externem Javascript

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
	onload="initEventListener()">
  <script type="application/x-javascript" src="js/edit.js"/>
  <label control="myInput" value="Html-Quelltext:"/>
  <textbox id="myInput" multiline="true" cols="40" rows="2" value=""/>
  <button id="submitButton" label="Speichern"/>
</window>
Javascript zum Hinzufügen eines Eventlisteners

function initEventListener(){
	document.getElementById('submitButton').addEventListener('command',function(){alert('hallo');}, true)
}

Overlays

Overlays sind Überlagerungen wie sie beispielsweise aus Navigationssystemen bekannt sind. Bei Navigationssystemen werden z.B. die OVI's nachträglich auf die Karte drauf gelegt. Das selbe Verhalten kann in XUL-Programmen mit Overlays erzeugt werden, damit nachträglich weitere Informationen dargestellt werden. Bei Updates werden z.B. Overlays verwendet um neue Menüeinträge hinzuzufügen ohne die Original-Datei anpassen zu müssen. Es können außerdem Teilbereiche von Benutzerinterfaces durch Overlays überschrieben oder wiederverwendet werden. Meistens werden Overlays jedoch verwendet um Browsererweiterungen, wie die Anpassung des Kontextmenüs, zu realisieren.

Wie werden Overlays eingefügt?

Der XUL-Runner konkateniert die Inhalte der selben IDs und fügt somit die Inhalte des Overlays in die Originaldatei ein. In den Overlays können noch weitere Positionierungsattribute festgelegt werden, die bestimmen wo innerhalb eines Elementens das Einfügen vorgenommen werden soll.

XUL-Programm mit einem Menü welches per Overlay um den Eintrag Close erweitert werden soll.


<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
	onload="initEventListener()">
  <script type="application/x-javascript" src="js/edit.js"/>
  <menubar id="sample-menubar">
    <menu id="action-menu" label="Datei">
	  <menupopup id="action-popup">
	    <menuitem name="New" label="New" />
		<menuitem name="Open" label="Open" />
		<menuitem name="Save" label="Save" />
	  </menupopup>
	</menu>
  </menubar>
  <label control="myInput" value="Html-Quelltext:"/>
  <textbox id="myInput" multiline="true" cols="40" rows="2" value=""/>
  <button id="submitButton" label="Speichern"/>
</window>

Overlay-Code


<?xml version="1.0"?>
<overlay id="singelItemEx" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <menupopup id="action-popup">
    <menuitem name="Close" label="Close" />
  </menupopup>
</overlay>

Overlay in chrome.manifest Laden


content example3 file:content/
overlay chrome://example3/content/example3.xul chrome://example3/content/overlay.xul
			

In der chrome.manifest wird definiert das beim Laden von example3.xul das Overlay overlay.xul angewendet werden soll.

Menü ohne Overlay

mit Overlay

Menü mit Overlay

ohne Overlay


XPCom

XPCom ist ein Plattform übergreifendes Component Object Model welches folgende Hauptfunktionalitäten mitbringt: Datei und Memory Management, Threads und Standard Datenstrukturen (Strings, Arrays, ...)
XPCom kann über sogenannte Bridges angesprochen werden, welche zur Zeit für Javascript, Java, Pyton und C++ extistieren. Im weiteren wird lediglich die Javascript Bridge XPConnect betrachtet, da diese die in Firefox-Plugins am häufigsten genutzt wird.

Beispiel zum Abspeichern einer Datei


function saveFile(fileName, val){
   // Privilegien holen um auf das Dateisystem zuzugreifen
   try {
      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   } catch (e) {
      alert("Permission to save file was denied.");
   }
   //Datei öffnen und falls sie nicht existiert erzeugen
   var file = Components.classes["@mozilla.org/file/local;1"]
             .createInstance(Components.interfaces.nsILocalFile);
   file.initWithPath(fileName);
   if (file.exists() == false) {
     file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420 );
   }
   //Outputstream erzeugen
   var outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
            .createInstance(Components.interfaces.nsIFileOutputStream);
   outputStream.init( file, 0x04 | 0x08 | 0x20, 420, 0 ); 
   //UTF-8 Konverter erzeugen
   var uc = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
     .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
   uc.charset = "UTF-8";
   //Daten in UTF8 umwandeln
   var data_stream = uc.ConvertFromUnicode(val);
   //Daten in Datei schreiben
   var result = outputStream.write(data_stream, data_stream.length );
   //Datei schließen
   outputStream.close(); 
}