Mendelova univerzita v Brně Problematika vývoje softwarových aplikací v jazyce XUL pro platformu Mozilla Bakalářská práce Vedoucí práce: Ing. Jan Kryštof, PhD. Petr Ondrejka Brno 2011
Děkuji vedoucímu práce Ing. Janu Kryštofovi, PhD. za podnětné připomínky a čas věnovaný konzultacím.
Prohlašuji, že jsem bakalářskou práci vypracoval samostatně a s použitím zdrojů uvedených v seznamu literatury. V Brně dne
4 Abstract Ondrejka P. Problems of software application development in XUL for Mozilla platform. Bachelor Thesis. Brno, 2011. This labour is concerned with development options for Mozilla software platform. We meet with basic principles of the platform and its single parts such as XUL, XBL, XPCOM interface and layers like XPConnect and LiveConnect. Main concern is to explore options of XUL as an instrument for declarative implementation of presentation layer and options of communication between interface elements and application layer. As practical part of this labour, the demostrating application for object reservation is built. Its essence is to show principles of Mozilla platform described in other parts of the labour. Reservation system gives the ability to reserve some real world objects to the users. They link the reservation with their name and with particular time. Application is based on three-layer architecture. The presentation layer is represented by XUL elements. Application layer by JavaScript code and other functionality that can t be implemented in JavaScript by two program modules written in C++ and Java programming languages. Data layer is composed of DBMS MySQL. Keywords: Mozilla, XUL, XBL, XPCOM, XPConnect, LiveConnect, Reservation system, Mozilla platform development Abstrakt Ondrejka P. Problematika vývoje softwarových aplikací v jazyce XUL pro platformu Mozilla. Bakalářská práce. Brno, 2011. Tato práce se zabývá možnostmi vývoje aplikací pro softwarovou platformu Mozilla. Seznamujeme se zde se základními principy platformy a jejími dílčími částmi, jako jsou jazyky XUL, XBL, rozhraní XPCOM a vrstvy XPConnect a LiveConnect. Hlavní důraz je pak v práci kladen na průzkum možností jazyka XUL jakožto prostředku pro deklarativní implementaci prezentační vrstvy a možností komunikace mezi prvky uživatelského rozhraní a aplikační vrstvou. Jako praktická část práce je vytvořena demonstrační aplikace pro rezervaci objektů. Jejím cílem je prakticky ukázat principy platformy Mozilla zmíněné v ostatních částech práce. Rezervační systém umožňuje jeho uživatelům rezervovat objekty z reálného světa vlastním jménem a na určitou dobu. Aplikace je navržena z pohledu třívrstvé architektury. Prezentační vrstvu reprezentují prvky jazyka XUL. Aplikační vrstvu pak kód JavaScript a ostatní funkčnost, která není zajistitelná JavaScriptem, dva programové moduly v jazycích C++ a Java. Datovou vrstvu potom tvoří SŘBD MySQL. Klíčová slova: Mozilla, XUL, XBL, XPCOM, XPConnect, LiveConnect, Rezervační systém, vývoj na platformě Mozilla
Obsah 1 Úvod... 7 2 Cíl práce... 8 3 Platforma Mozilla... 9 3.1 Architektura platformy... 9 3.1.1 Vrstevnatá architektura... 9 3.1.2 XPCOM model... 10 3.1.3 Podpora XML... 10 3.1.4 Model zobrazení obsahu Gecko... 10 3.1.5 Vlastní elementy a objekty... 11 3.1.6 Integrace GUI... 11 3.1.7 Přenositelnost... 11 3.1.8 Rozšiřitelnost... 12 3.1.9 Zabezpečení... 12 3.2 Schéma platformy Mozilla... 13 3.3 Jazyk XUL... 14 3.3.1 XULRunner... 14 3.3.2 Komponenty rozšíření k Mozilla aplikacím (Extensions)... 14 3.3.3 Struktura jazyka XUL... 14 3.3.4 Zpracování obsahu dokumentu... 14 3.3.5 Přístupová práva dokumentu... 15 3.3.6 Různé typy DOM dokumentu... 15 3.3.7 Organizace balíků (komponent)... 15 3.3.8 Soubory manifestu... 16 3.4 XULRunner první aplikace... 17 3.5 Základní použití XUL... 20 3.5.1 Vyvolávání a obsluha událostí... 20 3.5.2 Manipulace s událostmi... 20 3.5.3 Práce se seznamy... 21 3.5.4 Hierarchické stromy... 22 3.5.5 Selekce ve stromu... 23 3.6 Přidávání funkcionality XUL prvkům... 23 3.7 Jazyk XBL... 24 3.7.1 Dědění atributů... 25 3.7.2 Přidávání vlastností elementům... 26 3.7.3 Přidávání metod elementům... 27 3.7.4 Přidávání obsluhy událostí elementům... 28 3.7.5 Dědění v XBL... 28 3.8 Rozhraní XPCOM... 28 3.8.1 XPConnect... 29 3.8.2 Jazyk definice rozhraní IDL... 29 3.8.3 Vytváření XPCOM komponent... 29 3.8.4 Speciální XPCOM komponenty... 31 3.9 Kritika XPCOM... 31 3.10 LiveConnect... 31 3.10.1 Java Plug-In... 32 3.10.2 Wrappery (obálky)... 32 3.10.3 Práce s Java objekty v JavaScriptu... 32 3.10.4 Konverze datových typů mezi JavaScriptem a Javou... 33 5
Obsah 6 3.11 Vytvoření zásuvného modulu do prohlížeče Firefox... 37 4 Řešení systému pro rezervaci objektů... 39 4.1 Vlastní XPCOM komponenty... 39 4.1.1 Vytvoření potřebných souborů... 39 4.1.2 Build knihovny... 41 4.1.3 Testování... 42 4.1.4 Vrácení pole hodnot... 43 4.2 Práce s vlastním Java objektem v JavaScriptu... 45 4.2.1 Bližší pohled na nastavení práv pro JRE... 47 4.3 Aplikace Rezervační systém... 48 4.3.1 Neformální specifikace... 48 4.3.2 Analýza aplikace... 49 4.3.3 Prezentační vrstva... 49 4.3.4 Datová vrstva... 53 4.3.5 Aplikační vrstva... 54 5 Diskuse a závěr... 57 6 Seznam použité literatury... 58 7 Seznam obrázků a tabulek... 60 8 Přílohy... 61 8.1 Popis nejpoužívanějších XUL elementů... 61 8.3 Mapa případů použití... 85 8.4 Robustní diagramy k aplikaci Rezervační systém... 86 8.5 Třídní diagramy objektů CppServiceImpl a JavaServiceImpl... 91 8.6 Entity Relationship Diagram... 93
7 1 Úvod Platforma Mozilla je nástroj pro vývoj softwaru, který zahrnuje zpracování XML dokumentu, skriptovací jazyky a softwarové objekty. Používá se pro vytváření interaktivních aplikací zaměřených na uživatelský komfort a vysokou funkčnost. Tato práce představuje přehled této platformy a návod na její použití při praktických úkolech. Mozilla podporuje speciální styl vývoje software rychlý vývoj aplikací (RAD Rapid Application Development). O RAD hovoříme v případě, když programátoři využívají k vývoji aplikací účinné nástroje, které již obsahují velké množství základní funkčnosti. To jim umožňuje zaměřovat se na řešení problémů vyšší úrovně. Platforma Mozilla je tedy nástroj pro rychlý vývoj aplikací. Jednou ze strategií pro RAD je vytváření složitých webových aplikací. Tato práce se zabývá principy jak vytvořit nejen webovou aplikaci, ale i aplikace, ke kterým není potřeba webový prohlížeč. V mysli lidí je Mozilla úzce spojena s webem. Mozilla je však mnohem více než webové prohlížeče. Zde jsou některé statistiky: Mozilla obsahuje přes 1 000 objektů a 1 000 rozhraní. Podporuje mnoho standardů jako W3C (Word Wide Web Consortium), IETF(the Internet Engineering Task Force) nebo ECMA (European Computer Manufacturers Association). Mozilla má mnoho milionů uživatelů, stovky zaměstnanců firmy Netscape, tisíce dobrovolných vývojářů. Prostředků pro popis uživatelských rozhraní je mnoho. Některé existují jako objekty s již implementovanou základní funkčností, jiné slouží pouze pro popis prvků rozhraní. Základní funkčnost se potom přidává odděleně. Vývojáři mohou využít oddělenosti těchto nástrojů od funkční vrstvy ke zvýšení přenositelnosti kódu. Jedním z takto koncipovaných prostředků je značkovací jazyk XUL. Mozilla jej využívá pro popis většiny grafických uživatelských rozhraní. Obsahuje velké množství viditelných prvků na výstupu i prvků pro definici rozložení. Tento jazyk je možné použít namísto HTML se stejnou, ne-li vyšší hodnotou pro koncové uživatele. XUL naproti HTML nabízí elementy, které jsou podobné oknům a ovládacím prvkům, jaké známe z grafického prostředí systému Windows. Práce s tímto jazykem je snadná, aplikace jsou rychle rozšiřitelné. Přenositelnost kódu je omezena pouze na platformu Mozilla, nikoli na operační systém. Praktická část, tedy systém pro rezervaci objektů, potom dává dohromady poznatky nabyté v této práci. Využívá tak velkou část platformy Mozilla a čtenář získá přehled o několika frameworcích tvořených touto platformou.
8 2 Cíl práce Práce se zaměřuje na vývoj plnohodnotných aplikací pro platformu Mozilla. Aby nevznikla pouze grafická podoba uživatelského rozhraní, je třeba vyvinout i určitou funkcionalitu, která pokrývá potřeby prezentační a aplikační logiky dané domény. K implementaci funkcionality se v rámci platformy Mozilla využívá jazyk JavaScript, který ovšem v mnoha případech nepokrývá potřeby, které současný vývoj adresuje. Pokud se výchozí skriptovací jazyk Mozilly nehodí pro danou množinu případů, je třeba dodat alternativní řešení. Cílem této práce je prozkoumat a popsat možnosti v oblasti implementace funkčních aspektů pomocí rozhraní XPCOM a komponent C++ a Java. Druhotným cílem je vytvořit demonstrační aplikaci s použitím obou komponent. Dosažení cíle práce zahrnuje: průzkum a popis základních konceptů platformy Mozilla, průzkum a popis možností komunikace mezi prvky uživatelského rozhraní a aplikační vrstvou tvořenou (mimo jiné) komponentami C++ a Java, implementaci demonstrační aplikace využívající rozhraní XPCOM.
9 3 Platforma Mozilla Softwarová platforma je software, který programátoři používají jako odrazový můstek k řešení problémů vyšší úrovně. Díky vlastnostem platformy je jednodušší vytvářet funkčnost na vysoké úrovni. Programátoři nemusí ztrácet čas vytvářením základní funkčnosti pomocí jazyků jako C. Čtyři velké odrazové můstky v Mozille jsou XUL, JavaScript, RDF, a XPCOM. XUL je XML dialekt použitý ke konstrukci uživatelského rozhraní, JavaScript je skriptovací jazyk se syntaxí podobnou C, RDF je dialekt XML používaný k ukládání dat a XPCOM (Cross Platform Component Object Model) je objektový model k propojování a řízení systému. Hlavní síla platformy Mozilla je v budování vizuálních, interaktivních aplikací. Mozilla není určena k psání ovladačů, serverových systémů nebo systémů dávkového zpracování. 3.1 Architektura platformy Platforma Mozilla se snaží plnit různé potřeby programátorů. Aby tyto potřeby byly od sebe implementačně oddělené a fungovaly jako samostatné moduly, byla zavedena vrstevnatá architektura. 3.1.1 Vrstevnatá architektura Nejnižší vrstva platformy řídí a implementuje velkou množinu objektů. Tyto objekty spolupracují v rámci jediného spustitelného souboru podle vestavěného systému zprostředkování. Mozilla potřebuje zprostředkovatelský systém, který je vysoce přenosný, protože běží na mnoha platformách. Byl vytvořen vlastní systém pro tento účel. Nazývá se XPCOM a je jádrem této platformy. Přímý přístup k XPCOM je možný pouze z jazyků C a C++. Systém XPCOM běží na mnoha různých operačních systémech. Na vrcholu XPCOM je velmi tenká vrstva tzv. XPConnect. XPConnect poskytuje rozhraní mezi JavaScriptem a XPCOM. Jazyk JavaScript je flexibilní a slabě typový jazyk, který může manipulovat s XPCOM objekty velmi snadno. Tato vrstva poskytuje programátorovi velkou knihovnu objektů. Ta se skládá ze všech XPCOM objektů v platformě. Některé z objektů dostupných v rámci platformy jsou velké, sofistikované a dokážou zpracovat XML obsah. Tyto objekty náleží DOM vrstvě. Namísto analýzy XML přímo může programátor použít objekty platformy a zpracovat XML dokument. Skripty mohou potom pracovat s velkým množstvím vytvořených DOM objektů vzniklých z dokumentu XML. Tato vrstva DOM je běžná ve většině vývojových prostředí, kde se zpracovávají XML včetně webových stránek v XHTML. U těchto objektů se může vyskytovat bezpečnostní omezení. DOM vrstva poskytuje prostředí pro řadu na XML založených jazyků a navíc HTML Prostředí XUL je také založené na XML. Tato vrstva je výchozím bodem pro GUI (grafická uživatelská rozhraní). Některé XPCOM objekty provádí operace s GUI např. rozložení prvků a vykreslování. Objekty, které tohle provádí, jsou součástí jádra Gecko Mozilla Platformy. Tyto vysokoúrovňové objekty automatizují zobrazení XML dokumentů, grafiky a textu. Pokud programátor potřebuje zobrazit nějaký obsah, může skript předat obsah těmto objektům pro uspořádání a vykreslování. Tuto část platformy můžeme vidět v každém okně webového prohlížeče. Mozilla také obsahuje aplikační shell, který váže mnoho z XPCOM objektů dohromady ve spustitelný program. Tento program je schopen zautomatizovat a koordinovat mnoho úkolů, jako je připojení k serveru, základní správa dokumentů a instalace procesů. Aplikační shell spolu s mnoha speciálními XPCOM objekty představuje framework. To je použitelnější než pasivní knihovny, které neslouží k ničemu, dokud se programátor
3 Platforma Mozilla 10 nerozhodne je používat. Aplikační shell poskytuje organizaci a integraci vlastností, které umožňují spustit aplikace na platformě Mozilla. Soubor mozilla.exe je kopie platformy zabalená v rozsáhlém aplikačním shellu. Podstatná část práce programátora může být provedena pouze vytvořením XML dokumentů. Ty jsou pak dodávány shellu, který se postará o vytvoření fungující aplikace z XML dat. Nicméně programátor může používat jednotlivé vrstvy individuálně. [1] 3.1.2 XPCOM model Velká síla Mozilly je v její vnitřní struktuře. Na nejnižší úrovni je platforma sama napsána v C a C++. V případě jednoduchého C/C++ programu neznamená přidávání funkcí novou kompilaci a linkování objektů. U velkých projektů je to nepraktické. Jedním z důvodů je, že výsledný program bude velmi robustní a neefektivní. Má-li několik různých projektů použít software, každý z nich vyžaduje pouze jeho určitou část. Jinými slovy každý z nich může požadovat pouze část platformy. Každý projekt by musel měnit platformu, která je nepřenositelná, nebo by musel existovat s množstvím nepotřebných objektů. V těchto případech je potřeba zvolit vhodnější přístup. Pokud mají všechny objekty společné rozhraní, které může speciální typ objektu zvaný zprostředkovatel použít, pak může být zacházeno s velkou množinou objektů stejným způsobem. Potom se říká, že objekty mají určitou uniformitu. Objekty mají svoje rozhraní a komponenty (samostatné části). Téměř celá Mozilla se skládá z XPCOM komponent a většina těchto komponent je skriptovatelných v JavaScriptu. Mnohé z nich implementují Web protokoly nebo jiné síťové standardy. Tento model plus dostupné síťové komponenty mohou způsobit, že Mozilla vypadá jako miniaturní verze frameworku.net. Více o modelu XPCOM je uvedeno v pozdější části práce. Viz 3.8 Rozhraní XPCOM. [1] 3.1.3 Podpora XML Softwarová podpora pro standardy XML závisí na úhlu pohledu. Program může pouze být schopen číst XML dokument stejně jako souborový filtr nebo může kompletně analyzovat XML data jako XML databázový server. Mozilla leží někde mezi těmito dvěma extrémy. Mozilla lépe pracuje s XML standardy místo toho, aby jen četla dokumenty tohoto formátu. Má také značnou infrastrukturu pro správu získaných XML dokumentů, zejména model RDF. Mozilla podporuje také různé transformační techniky např. slučování a filtrování dokumentů, správu fragmentů dokumentů, aktualizace, odstraňování apod. Seznam podporovaných XML aplikací je: XML, XML jmenné prostory, XLink, XHTML (a HTML), MathML, SVG, XSLT (Extensible Stylesheet Language Transformations), RDF, SOAP, WSDL (Web Services Description Language) a XML Schema. Podporuje také dvě unikátní XML aplikace, které jsou pro tuto platformu specifické XUL a XBL. XUL dokumenty slouží pro uspořádání grafických widgetů. XBL dokumenty představují vazby, které vzájemně prolínají JavaScript a XML. Mozilla podporuje DTD (Document Type Definition) pro mnoho výše uvedených XML aplikací. [1] 3.1.4 Model zobrazení obsahu Gecko K zobrazení XML obsahu je potřeba systém, který to provede. To je úkol vykreslovacích objektů uvnitř platformy, které jsou součástí subsystému displeje Gecko. Pravidla určující rozložení prvků XML (a zejména rozložení prvků HTML) se měnily v posledních několika letech. Tam, kde se používají k zobrazení dat např. v HTML, jsou tato pravidla sdružena do standardů jako je CSS, DSSSL (Document Styl Semantics and Specification Language), a XSL-FO (XSL Formatting Objects). Tento trend se odráží v Mozille, kde je veškeré
3 Platforma Mozilla 11 rozložení řízeno moderním standardem CSS2, který zahrnuje mnoho vylepšení specifických pro Mozillu. Výkonný engine CSS2 je také srdcem zobrazovacího systému Gecko. XML dokumenty nejsou neměnné. Moderní nástroje pro zobrazení potřebují sofistikovaný model zobrazení pro podporou všech druhů dynamických změn obsahu. Mozilla má zobrazovací systém třetí generace, který reprezentuje jádro Gecko. Na jednotlivé strategie tohoto zobrazovacího systému se podíváme, jak byly uplatňovány historicky. Ačkoli seznam odkazuje na XML, nejznámějším příkladem je zobrazovací systém, který zobrazuje HTML. [1] Mark I strategie. Čte XML elementy jeden po druhém a okamžitě je zobrazuje. Proces zobrazování se přeruší v případě, že není dostatek elementů na vstupu, aby systém zjistil další krok. Uživatel musí v tomto případě čekat. Zastaralý přístup. Mark Ib strategie. Načte všechny XML elementy do paměti, což způsobuje časovou prodlevu. Potom se analyzuje dokument, který se následně zobrazí celý najednou. Žádné dnešní prohlížeče nepoužívají tento přístup. Pouze sytém transformace XML prvků XSLT provádí dávkové zpracování podobným způsobem za použití speciálního softwaru. Mark II strategie. Přečte XML elementy jeden po druhém a zobrazí stránku pomocí zástupných symbolů obsahu, které se očekávají, ale dosud nebyly přečteny. Když přijde skutečný obsah, dynamicky se nahradí zástupné symboly skutečným obsahem. Tuto techniku používají Internet Explorer 4.0+ a Mozilla 1.0+. Mark III strategie. Přečte XML elementy jako Mark II a navíc řídící informace. Když uživatel nebo server manipuluje s řídicími informacemi, prochází se nebo se odstraňuje odpovídající obsah a aktualizuje se podle toho zobrazení. To se děje i poté, co je dokument plně načten. 3.1.5 Vlastní elementy a objekty Mozilla podporuje mechanismus na provázání elementů a kompilovaných objektů zaručujících určitou funkčnost. Tento mechanizmus se nazývá specifikační jazyk XBL. Jazyk XBL je opět dialektem XML. Proces vázání elementů a kompilovaných objektů se nazývá binding (svazování, propojení). Objekty mohou mít jak charakter všech služeb včetně funkčnosti již zahrnutých XPCOM objektů, tak objektů vlastních. [1] 3.1.6 Integrace GUI Mozilla je nástroj orientovaný na vykreslování určitých prvků, který je velmi odlišný od jiného Open Source nástroje jako Apache. Apache pouze čeká na jednoduchých síťových připojeních. Mozilla je úzce napojena na uživatele a uživatelské prostředí. Obsahuje několik strategií pro práci s GUI. Na nejnižší úrovni spoléhá na widgety GUI z vhodných nativních nástrojů pro aktuální platformu. Jsou to GTK na Linuxu, Win32 na Windows a toolkit Macintosh. Na desktopové úrovni reaguje Mozilla na operace související s hlavním oknem aplikace jako je fokus, nahrávání ikon nebo ukončení. Zahrnuje také multiformátové kopírování přes schránku (typické operace s klávesovými zkratkami ctrl+c, ctrl+v). Některé formáty tedy mohou být zachovány, pokud se kopírují do aplikací jako Microsoft Word. Mozilla podporuje operace táhni a pusť (drag and drop) v rámci aplikací. To ale někdy nefunguje automatizovaně a je třeba tyto funkce ručně implementovat. Jedna z nejsilnějších stránek Mozilly na úrovni aplikace je jazyk XUL, který umožňuje propojit grafické prvky velmi jednoduchým a efektivním způsobem. [1] 3.1.7 Přenositelnost Mozilla běží na mnoha různých operačních systémech a desktopech. Produkty Mozilla jsou podporovány minimálně následujícími operačními systémy:
3 Platforma Mozilla 12 UNIX: Linux i386/powerpc, FreeBSD, HP-UX, Solaris i386/sparc, AIX, Irix Mini počítače: OpenVMS Osobní počítače: Windows 95/98/Me/NT/XP, MacOS 9.x / X, OS / 2, BeOS Existují také experimentální projekty s jinými platformami jako např. Amiga. Většina podporovaných funkcí je určena pro shodné použití napříč platformami. Konkrétní soubory, které jsou potřebné k postavení aplikace Mozilla (XUL, CSS, DTD, JavaScript, RDF, atd.), jsou všechny přenosné formáty. Teoreticky by měla aplikace založená na platformě Mozilla běžet na všech operačních systémech, na kterých je podporovaná samotná platforma, bez nutnosti přepisovat kód. V praxi se však mohou vyskytovat drobné rozdíly a je třeba aplikace testovat. [1] 3.1.8 Rozšiřitelnost Síla Mozilly je v tom, že je platformou, a nejen produktem omezeným na běh v jednom prostředí. Mozilla je prostředí samo o sobě. Slabinou je, že jen verze 1 je velmi rozvinutá. Platforma nemusí být tak flexibilní nebo tak kompletní, jak by někteří očekávali. Mohou být přidány nové objekty (i XPCOM objekty), nové XML značky, stejně jako celé nové aplikace. Protože zdrojový kód platformy je k dispozici, je možné jakékoli vylepšení nebo jiné změny. Experimentování s platformou je poměrně jednoduché a proto se mnoho vývojářů pokouší o vylepšení. Web www.mozdev.org sdružuje mnoho nadšenců. [1] 3.1.9 Zabezpečení Mozilla podporuje funkce zabezpečení Netscape 4.x včetně "Same Origin" politiky. Tato politika zabezpečuje, že rizikové operace jako zápis souboru jsou silně omezeny. Nebezpečná operace, která je vyvolána z internetové lokace (URL), může být aplikována pouze na zdroje, které jsou příchozí ze stejné lokace. Toto omezení umožňuje Java appletům komunikovat pouze se servery odkud pocházejí. Podobně je umožněno HTML nebo XUL aplikacím odesílat data na webový server, na kterém vznikly. Nejpozoruhodnější aspekt bezpečnosti v platformě je skutečnost, že aplikace instalované ve speciálním umístění /chrome nemají žádná bezpečnostní omezení. Nicméně omezení předepsaná v operačním systému stále platí. Tato platforma má několik bezpečnostních modelů, které jsou popsány v dalších částech práce. Standardní instalace platformy zahrnuje podporu pro většinu digitálních šifrovacích standardů a certifikátů certifikační autority. [1]
3 Platforma Mozilla 13 3.2 Schéma platformy Mozilla Obrázek 1: Schéma platformy Mozilla [1]
3 Platforma Mozilla 14 Berme toto schéma spíše orientačně. Většina položek schématu bude popsána v dalších částech práce stejně jako vztah mezi nimi. 3.3 Jazyk XUL XUL (XML User Interface Language) je deklarační značkovací jazyk založený na XML, vyvinutý pro platformu Mozilla a sloužící pro specifikaci uživatelských interfaců (rozhraní). Jádro aplikací Mozilla Gecko poskytuje implementaci pro layout rozhraní specifikovaném v jazyce XUL. XUL aplikace je aplikace jazyka XUL, která může využívat dalších Mozilla technologií a technologií jako např. JavaScript, CSS, XBL a XPCOM. 3.3.1 XULRunner Je runtime prostředí pro běh XUL aplikací. Ty vlastně běží na dvou vrstvách: vrstva uživatelského rozhraní, která je odlišná pro každou aplikaci, a vrstva (platforma) společná všem aplikacím, která uživatelské rozhraní implementuje. Tato platforma se nazývá XULRunner. XULRunner zahrnuje Gecko, Necko API pro síťovou komunikaci a další komponenty. Umožňuje vývoj komponent rozšíření pro platformu Mozilla ve formě desktopové aplikace (s každou komponentu se pracuje jako se samostatnou aplikací). 3.3.2 Komponenty rozšíření k Mozilla aplikacím (Extensions) Rozšiřující komponenty (dále jen komponenty) přidávají novou funkcionalitu k Mozilla aplikacím. Jsou to samostatné balíky, které se nainstalují a integrují s aplikací, ke které mají přidávat funkcionalitu. Nová funkcionalita může spočívat ve vytvoření jednoduchého ovládacího tlačítka, ale také k vytvoření kompletně nových vlastností. Většinou slouží k individuálním potřebám uživatelů, aby uspokojily potřebu specifické funkcionality, vyžadované daným uživatelem. Všechny komponenty jsou rozšiřující prvky (add-on). Addony mohou být také plug-iny, jazykové balíčky, grafická témata apod. Komponenty jsou obvykle malé balíčky souborů XUL, JavaScriptu, CSS a dalších, integrovaných do jednoho souboru poskytujícího finální funkcionalitu. 3.3.3 Struktura jazyka XUL XUL má stejnou strukturu jako ostatní značkovací jazyky založené na XML (např. xhtml). Dokument je sestaven z elementů, které mohou mít atributy. Elementy se potom mohou graficky jevit jako celá řada prvků ovládací tlačítka, textové popisy, seznamy, menu lišty, přístrojové lišty apod. Elementy mají počáteční značku a koncovou značku. Tyto značky dodávají obsahu elementu význam, tak aby jej zpracovávající program správně interpretoval. Může k nim být přiřazena dodatečná funkčnost, styly CSS stejně jako u dalších jazyků založených na XML a při zpracovávání tvoří hierarchickou stromovou strukturu. [7] 3.3.4 Zpracování obsahu dokumentu Nejprve je třeba určit zdroj dat ke stavbě dokumentu. Ten specifikujeme adresou URL. Zpracovávací program (např. Mozilla Firefox) stáhne data a interpretuje je jako XUL kód. Potom transformuje XUL kód do dokumentového stromu. Strom se skládá z množiny objektů, které mohou být zobrazeny na výstupu (obrazovce). Zobrazování je potom v režii technologie CSS, respektive programu, který zobrazování implementuje. Funkce XULu jsou zpracovávány podobným způsobem. [7]
3 Platforma Mozilla 15 3.3.5 Přístupová práva dokumentu Při zpracování obsahu ze vzdáleného zdroje (např. http://localhost/~username/) jsou operace vyplývající z dokumentu omezené ve svých právech. Nezáleží, zda je typ dokumentu xhtml, XUL, nebo jiný. Pokud mají mít neomezená přístupová práva (což naše komponenty vyžadují), je nutné tyto soubory nainstalovat a registrovat do systému chrome. Zpracovávající program stáhne soubory a lokálně je nainstaluje a registruje do svého systému chrome. Systém chrome slouží k přidělení přístupových práv na maximum. Lokální soubory specifikované URL protokolem chrome:// mají tedy chrome přístupová práva. Kód běžící pod těmito právy je oprávněn provádět všechny operace (např. přístup k lokálním souborům, přístup k nastavení, atd.). To je rozdíl např. oproti webovým stránkám, jejichž kód je omezen (pokud nejsou podepsány digitálním certifikátem). Pokud se odkazujeme na nějaký zdroj protokolem chrome://, obvykle jsou zde umístěny komponenty (extensions), tedy jejich kód (soubory *.xul, *.js, *.css a další). [7] XUL kód je možné nahrát třemi způsoby: ze vzdáleného zdroje, z lokálního souborového systému, z instalovaného balíku (u komponent prohlížeče). 3.3.6 Různé typy DOM dokumentu Při načítání kódu prohlížeč Firefox vytváří různé typy DOM dokumentů. Záleží to vždy na typu dokumentu specifikovaném v http hlavičce, popř. v metadatech fyzického souboru. Firefox vytváří tři typy DOM dokumentů HTML, XML a XUL. XML typ vytváří základní objektový model, od kterého zbylé dva dědí atributy i metody. Je to logické, neboť xhtml a XUL jsou jazyky odvozené od XML. Je potřeba si dávat pozor na rozdíly mezi HTML typem DOM dokumentu a XUL typem. Rozdíly plynou především z různých elementů těchto jazyků. Např. vlastnost document.forms neexistuje v DOM modelu typu XUL, protože jazyk XUL neobsahuje formuláře, které jsou v HTML. [7] 3.3.7 Organizace balíků (komponent) Balík komponenty je vlastně komponenta reprezentovaná jedním fyzickým souborem, který je instalovaný (instalace znamená, že je balík určen souborem manifestu, viz dále) v rámci nějaké aplikace využívající platformu Mozilla. Balík může být uložen jako adresář nebo jako JAR soubor. Tento soubor archivuje více souborů (*.xul, *.js, *.css a další), které obsahují kód definující funkcionalitu komponenty. Každá komponenta je specifikována jedním chrome URL. Všechny komponenty jsou obvykle fyzicky umístěné v adresáři chrome. Tím, že okopírujeme do tohoto adresáře soubory, neznamená, že budou mít automaticky přiděleny speciální přístupová práva a bude možno k nim přistupovat přes protokol chrome://. K tomu potřebujeme vytvořit soubor manifestu. Ten mapuje chrome URL na určité fyzické místo na disku. Jak vytvořit soubor manifestu si rozebereme dále. Mozilla interpretuje soubory obsažené v balíku a jejich parsovaný kód ukládá do paměti RAM, aby se zlepšil výkon v případě dalšího sezení (znovuspuštění kódu). Vyčleňuje si pro to část operační paměti, která tak slouží jako cache. Pokud jsou tyto soubory modifikovány, změny se neprojeví právě kvůli načítání z mezipaměti. K tomu, aby se změny projevily, je potřeba toto sdělit interpretu speciální instrukcí. V souboru user.js (soubor uživatelských preferencí v Mozilla Firefox) přidáme řádek pref("nglayout.debug.disable_xul_cache", true);. [7] V balíku jsou obvykle soubory, které mají pro aplikaci tři významy (content obsah, skin styl a locale další specifické soubory). Tyto soubory jsou uloženy ve třech různých adresářích odpovídajících významu souborů. Popis jednotlivých typů souborů:
3 Platforma Mozilla 16 Content (obsah) Okna a skripty. Je to deklarace oken a XUL elementů uživatelského rozhraní. V adresáři s content významem může být více XUL souborů. Skin Soubory stylů (CSS), obrázků a dalších souborů specifikujících vzhled. Ukládají se odděleně od XUL souborů, aby byly faktické elementy rozhraní odděleny od specifikace jejich zobrazení. Díky tomu stačí nahrát nový balík se styly, a rozhraní dostane úplně nový vzhled. Locale Lokální soubory. Všechen text, který se zobrazuje v oknech, se ukládá odděleně. Díky tomu může mít uživatel soubory s vlastním jazykem. Balík se obvykle nachází v podadresáři chrome. Typická adresářová struktura uvnitř balíku může vypadat následovně: Content: -- balík browser.jar v prohlížeči Firefox určuje část uživatelského rozhraní -- + /content +-+ /browser +- browser.xul +- browser.js -- soubory *.js a *.xul-- +-+ /bookmarks -- soubory záložek +-+ /preferences -- soubory uživatelského nastavení --... Skin: -- balík classic.jar v prohlížeči Firefox definuje styl zobrazení XUL elementů -- skin + /classic +-+ /browser +- browser.css -- soubory stylů +-+ /global -- globální soubory stylů --... Locale: Soubor en-us.jar popisuje jazykové definice pro každou komponentu. Texty v rámci rozhraní totiž mohou být v různých jazycích. V tomto případě popisuje americkou angličtinu. Obsahuje soubor *.dtd. [7] 3.3.8 Soubory manifestu Soubor manifestu popisuje balík a mapuje jeho umístění do chrome URL. Při spuštění Mozilla aplikace se prohledává adresář chrome pro soubor manifestu. Pokud je nalezen, adresy, které definuje na disku na každém řádku, budou mapovány do chrome URL. Soubor manifestu musí mít příponu.manifest a být uložen v kódování ASCII. Příklad souboru a jeho obsah: test.manifest uložen v <adresaraplikace>/<chrome>
3 Platforma Mozilla 17 Obsah: content tests file:///c:/testfiles/ Balíky, které jsou umístěny v C:\testfiles\ tak budou zpřístupněny přes chrome URL a budou mít speciální přístupová práva. Příklad odkazu přes chrome URL k souboru sample.xul v balíku tests je chrome://tests/content/sample.xul. chrome:// si můžeme představit jako alias pro cestu C:\testfiles\. Klasický vzor, jak takto specifikovat balíky v souboru manifestu, je následující: 'content <názevbalíku> <cesta>'. Pro JAR balíky je vzor podobný: jar:<nazevbaliku.jar>!/<cesta_v_baliku>. Klíčové slovo content říká, že balík je typu content. Balíky skin a locale jsou uvozeny odpovídajícím klíčovým slovem. [7] Další příklady obsahu souboru manifestu: content branding jar:browser.jar!/content/branding/ xpcnativewrappers=yes content browser jar:browser.jar!/content/browser/ xpcnativewrappers=yes overlay chrome://global/content/viewsource.xul chrome://browser/content/viewsourceoverlay.xul overlay chrome://global/content/viewpartialsource.xul chrome://browser/content/viewsourceoverlay.xul overlay chrome://browser/content/pageinfo.xul chrome://pippki/content/pageinfooverlay.xul skin browser classic/1.0 jar:classic.jar!/skin/classic/browser/ locale browser en-us jar:en-us.jar!/locale/browser/ Klíčové slovo overlay umožňuje zkombinovat obsah více balíků dohromady. Na konci řádku můžeme použít parametr xpcnativewrappers=yes. Některé webové stránky (jejich JavaScript kód) mohou přetěžovat nativní funkce nebo metody. Pokud je parametr xpcnativewrappers nastavený na hodnotu yes, skripty běžící v kontextu s vyššími právy nebudou volat tyto přetížené metody, ale nativní metody. Při definici cesty ke skinu nebo localu se uvádí za klíčové slovo skin (resp. locale) název balíku, ke kterému tyto náleží. Teprve potom následuje název vlastního balíku s definicí stylu nebo jazykovou definicí. U označení verze classic/1.0 je část 1.0 nepovinná. [7] 3.4 XULRunner první aplikace [8] Krok 1: Stáhnutí a instalace XULRunneru Na systém Windows můžeme XULRunner stáhnout z internetu z URL http://releases.mozilla.org/pub/mozilla.org/xulrunner/releases/. Instalace spočívá pouze v rozbalení stáhnutého archivu na disk do libovolné složky. Na systému GNU/Linux (Ubuntu, Xubuntu) a Mac OS X jsou instalace XULRunneru distribuovány spolu s instalací systému. Na systému GNU/Linux distribuce Kubuntu proveďte příkaz sudo apt-get install xulrunner v shellu. Krok 2: Vytvoření adresářové struktury aplikace Bez ohledu na operační systém vytvoříme následující adresářovou a souborovou strukturu na libovolném umístění: + /myapp +-+ /chrome
3 Platforma Mozilla 18 +-+ /content +- main.xul +- main.js +- chrome.manifest +-+ /defaults +-+ /preferences +- prefs.js +- application.ini +- chrome.manifest Všechny soubory jsou textové a můžeme je vytvořit v libovolném textovém editoru. Poslední soubor chrome.manifest v adresáři myapp je potřeba vytvářet pouze pro XULRunner od verze 2.0. Krok 3: Vytvoření application.ini V souboru application.ini jsou parametry aplikace. Jsou zde informace např. o tom, jak aplikace bude využívat platformu nebo konfigurační nastavení pro běh aplikace. Do souboru application.ini vložíme následující obsah: [App] Vendor=XULTest Name=Myapp Version=1.0 BuildID=20100901 ID=xulapp@xultest.org [Gecko] MinVersion=1.8 MaxVersion=2.* Parametry MinVersion a MaxVersion určují interval možných verzí jádra Gecko, které musí mít naše verze XULRunneru. Parametr Name musí odpovídat názvu v souboru manifestu (další krok). Krok 4: Vytvoření souboru manifestu Soubor manifestu určuje zdrojové soubory aplikace (soubory *.xul, *.js, *.css a další). Cílem je zpřístupnit tyto zdroje přes chrome URL a dát jim tak zvýšená práva při exekuci kódu. Podrobnější popis viz výše. Do souboru chrome.manifest v adresáři chrome vložíme následující obsah: content myapp content/ Do hlavního souboru manifestu v kořenovém adresáři aplikace pro XULRUnner 2.0 vložíme následující obsah: manifest chrome/chrome.manifest Krok 5: Nastavení předvoleb aplikace Soubor prefs.js říká XULRunneru název XUL souboru, který má použít jako hlavní okno aplikace. Do souboru prefs.js vložíme následující obsah: pref("toolkit.defaultchromeuri", "chrome://myapp/content/main.xul");
3 Platforma Mozilla 19 Krok 6: Vytvoření XUL souboru a JavaScript souboru: V souboru main.xul budeme definovat základní okno s jedním ovládacím tlačítkem a s elementem description, který bude reprezentovat nějaký textový popis. Tlačítko po stisku vyvolá událost, kterou odchytne JavaScript funkce showmore(), a odkryje textový popis v elementu description. Obsah main.xul je následující: <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window id="main" title="my App" width="300" height="300" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > <script type="application/javascript" src="chrome://myapp/content/main.js"/> <caption label="hello World"/> <separator/> <button label="more >>" oncommand="showmore();"/> <separator/> <description id="more-text" hidden="true">this is a simple XULRunner application. XUL is simple to use and quite powerful and can even be used on mobile devices.</description> </window> Obsah main.js je následující: function showmore() { document.getelementbyid("more-text").hidden = false; } Krok 7: Spuštění aplikace: Na systému Windows: přidáme soubor xulrunner.exe do proměnné prostředí PATH a přesuneme se do kořenového adresáře aplikace. Aplikaci spustíme příkazem: xulrunner.exe application.ini Na systému Mac OS X musíme nejprve aplikaci nainstalovat. Vytvoříme tím spustitelný balík pro Mac. /Library/Frameworks/XUL.framework/xulrunner-bin --install-app /<path>/<to>/myapp.zip Potom spustíme aplikaci příkazem /Library/Frameworks/XUL.framework/xulrunner-bin "/Applications/Finkle/TestApp.app/Contents/Resources/application.ini" Na systému GNU/Linux se přesuneme do kořenového adresáře aplikace a spustíme ji příkazem: xulrunner application.ini
3 Platforma Mozilla 20 3.5 Základní použití XUL Jazyk XUL disponuje velkým množstvím vlastních elementů. Používají se stejně jako prvky jiných jazyků založených na XML. Skládají se z počáteční značky, koncové značky, obsahu prvku a atributů. Podrobnější návod na vytváření základních elementů a jejich použití je uveden v příloze práce. V následujících částech budeme již předpokládat základní znalost XUL prvků uvedených v příloze. Následují příklady XUL událostí a vytváření hierarchických a nehierarchických seznamů. 3.5.1 Vyvolávání a obsluha událostí Abychom poskytli naší aplikaci nějakou funkčnost, musíme přidat skripty, které se spustí, když uživatel pracuje s dialogem. Funkčnost přidáváme obvykle JavaSript kódem podobně jako v HTML. Můžeme použít element script a JavaScript kód specifikovat přímo v souboru XUL nebo přidat atribut src a určit cestu k externímu souboru s JavaScript kódem. Příklady použití elementu script: <script src="findfile.js"/> <script src="chrome://findfiles/content/help.js"/> <script src="http://www.example.com/js/items.js"/> 3.5.2 Manipulace s událostmi Událost je moment s určitým významem, který může být vyvolaný buď uživatelem (např. kliknutí na ovládací tlačitko), nebo v kódu uměle. Podle významu události k ní přiřazujeme příslušnou obsluhu (handler). V našem případě budeme obsluhovat události v kódu JS, obvykle nějakou funkcí. V XUL existuje velké množství předdefinovaných událostí. Jsou určeny názvem události (např. událost mousemove je spuštěna při pohybu myši přes element asociovaný s touto událostí). Události v XUL mají stejný mechanismus jako DOM události. Události přiřazujeme k elementům buď pomocí atributu, nebo pomocí metody addeventlistener, která náleží elementu. Užívání atributu je běžnější a snazší na zápis. Hodnota atributu je JS kód, který slouží jako obsluha události. Název atributu začíná písmeny on a následuje názvem události (např. onmousemove= obsluha(); ). Pokud přiřazujeme obsluhu události zanořenému prvku (např. tlačítko button v hboxu), většina událostí se vyvolává pro všechny prvky v hierarchii okna (událost tedy obdrží jak window, tak hbox a button). [7] Jedna z nejpoužívanějších událostí je událost command. Je to událost, která je vyvolaná po aktivaci nějakého prvku (například stisk tlačítka). Je to v podstatě stejná událost jako v HTML událost click. V XUL existuje také událost click, ale znamená pouze stisk tlačítka myši, nikoli např. klávesy enter. Příklad ošetření události command: <button label="ok" oncommand="alert('button was pressed!');"/> Po vyvolání události command (stisku tlačítka) se zobrazí hlášení Button was pressed!. Nejdůležitější XUL události: click událost vyvolána stiskem a puštěním tlačítka myši. dblclick událost vyvolána dvojklikem myši. mousedown je stisknuto tlačítko myši, ale není ještě puštěno. mouseup puštěno tlačítko myši. mouseover vyvoláno, pokud myš překročí hranici elmentu směrem dovnitř. mousemove vyvoláno při pohybu myši nad elementem. mouseout vyvoláno, pokud myš opustí hranici elementu.
3 Platforma Mozilla 21 focus událost je vyvolána při označení elementu jako aktivní (obdrží fokus). keypress událost vyvolána při stisku a puštění klávesy (děje se tak při vyvolání události nejprve keydown a následně keyup). load při načtení elementu (u elementu window je vyvolána událost load po vytvoření objektového modelu DOM celého okna). close událost vyvolána při požadavku o zavření okna (uživatel stiskl zavírací tlačítko). drag při tažení elementu myší vznikne událost, která je mu předána. dragdrop při puštění elementu, který je tažen myší. input při změně textboxu uživatel stiskl klávesu, kterou změnil text v textboxu. 3.5.3 Práce se seznamy Jeden z komplexnějších prvků XUL element tree (strom). Strom může být použit k zobrazení řádků textu ve sloupcích. Seznam tak tvoří vlastně matici. Jednotlivé řádky a sloupce mohou být ve formátu tabulky nebo hierarchicky uspořádané (hierarchický seznam). Hierarchie stromů spočívá v tom, že každý záznam může mít řadu dalších podzáznamů a ty mohou mít další podzáznamy. Struktura stromu je tak velice podobná např. adresářové struktuře v souborovém systému. Strom také umožňuje uživateli změnit uspořádání, velikost a skrývat jednotlivé sloupce. [7] Strom se skládá ze dvou částí množiny sloupců a těla stromu. Sada sloupců je definována počtem treecol elementů, vždy jeden pro každý sloupec. Každý sloupec se zobrazí jako záhlaví v horní části seznamu. Druhá část, tělo stromu, obsahuje údaje zobrazitelné ve stromu a je vytvořena elementem treechildren. Stručný popis jednotlivých elementů tvořící strom: tree Ohraničuje začátek a konec stromu. treecols Tento element sdružuje treecol elementy. treecol Určuje sloupec stromu. Při použití tohoto prvku můžeme zadat další informace o tom, jak jsou data ve sloupcích seřazena, a jestli uživatel může měnit velikost sloupců. treechildren Hlavní část stromu, pro jednotlivé řádky dat. Tyto elementy netvoří samotný obsah stromu, ale pouze jeho hlavičku a způsob zobrazení. K vytvoření obsahu stromu používáme následující elementy: treeitem Obsahuje jeden řádek a všechny jeho potomky. Tento prvek slouží také jako položka, která může být vybrána uživatelem. treerow Řádek ve stromu, který by měl být umístěn uvnitř treeitem elementu. treecell Buňka stromu. Je to vlastně místo, kde se protne řádek a sloupec. Tento prvek je umístěn uvnitř treerow elementu. Tyto elementy jsou umístěné přímo v elementu treechildren. Příklad: <tree flex="1"> <treecols> <treecol id="sender" label="sender" flex="1"/> <treecol id="subject" label="subject" flex="2"/> </treecols> <treechildren> <treeitem> <treerow> <treecell label="joe@somewhere.com"/>
3 Platforma Mozilla 22 <treecell label="top secret plans"/> </treerow> </treeitem> <treeitem> <treerow> <treecell label="mel@whereever.com"/> <treecell label="let's do lunch"/> </treerow> </treeitem> </treechildren> </tree> Obrázek 2: Nehierarchický strom se dvěma sloupci V tomto tabulkovém stromu jsou 2 sloupce a 2 řádky. Sloupce jsou deklarovány pomocí dvou elementů treecol obklopené elementem treecols. Obsah je specifikován v elementu treechildren. Element treeitem v tomto případě plní stejnou funkci jako element treerow, protože neobsahuje žádné potomky. V buňce treecell je potom definován obsah. 3.5.4 Hierarchické stromy Tento typ stromů umožňuje k elementu treeitem připojit další element treechildren. Řádek, který je specifikován daným elementem treeitem, potom může být rozevírací podseznam. V tomto případě musí mít element treeitem atribut container s hodnotou true, aby mohl uživatel skrývat/odkrývat potomky. Tento podseznam je opět sestaven z elementů treeitem a treerow. Sem můžeme opět přidávat další potomky elementem treechildren. Základní řádky na nejvyšší úrovni stromu mají v hierarchii level 0. Potomci základních řádků mají level 1 a tak dále. Nesmí obsahovat oba dva. První sloupec musí být označen atributem primary a hodnotou true. To označuje, že buňky v tomto sloupci jsou rozevírací. Příklad: <tree rows="6"> <treecols> <treecol id="firstname" label="first Name" primary="true" flex="3"/> <treecol id="lastname" label="last Name" flex="7"/> </treecols> <treechildren> <treeitem container="true" open="true"> <treerow> <treecell label="guys"/> </treerow> <treechildren> <treeitem> <treerow> <treecell label="bob"/> <treecell label="carpenter"/> </treerow> </treeitem>
3 Platforma Mozilla 23 <treeitem> <treerow> <treecell label="jerry"/> <treecell label="hodge"/> </treerow> </treeitem> </treechildren> </treeitem> </treechildren> </tree> Obrázek 3: Hierarchický strom První sloupec je označen jako primary. V datové části stromu je jeden element treeitem. V něm je jednak vlastní řádek, tedy element treerow, a jednak element treechildren obsahující podstrom. V tomto podstromu jsou pak dva řádky. 3.5.5 Selekce ve stromu Uživatel může vybrat buď jeden řádek stromu, nebo více a s touto selekcí provést nějakou akci. Při výběru nastává událost select. Handler, který tuto událost odchytí, se nazývá onselect. Stejný název má atribut, který určuje kód na obsluhu. Ukázka: <tree id="treeset" onselect="alert('právě jste vybral řádek!');"> K tomu, abychom získali pořadové číslo řádku, který je označen, použijeme vlastnost stromu (strom je objekt) currentindex. První řádek má hodnotu 0. Číslo řádku má hodnotu bez ohledu na zanoření. Pokud na prvním řádku bude zanořený potomek se dvěma řádky, jejich pořadová čísla budou 0 a 1. Další řádek v základní větvi stromu potom bude mít index 2. Pořadové číslo se počítá jen na řádcích, které jsou zobrazeny. Pokud je tedy část stromu skryta, nezapočítává se. 3.6 Přidávání funkcionality XUL prvkům Pomocí XUL můžeme vybudovat komplexní uživatelské rozhraní. Můžeme připojit skripty, které pracují s rozhraním, a plnit různé úkoly. Nicméně existuje poměrně mnoho věcí, které nelze provést přímo JavaScriptu. Například pokud bychom chtěli vytvořit mail aplikaci, museli bychom psát skripty, které se musí připojit k mail serveru pro stahování a odesílání pošty. V JavaScriptu toho nedosáhneme. Další problémy mohou být práce se souborovým systémem, databází apod. [7] Jediným způsobem, jak řešit tyto problémy, je napsat nativní kód. Skripty potom budou tento nativní kód volat přes rozhraní. Na platformě Mozilla lze pro využívání nativního kódu v XUL aplikaci používat více přístupů. Jedním z nich je objektový model XPCOM (Cross-platform Component Object Model), který umožní vytváření tzv. komponent s funkcionalitou napsanou v nativním kódu. Tyto komponenty potom využíváme v JavaSriptu. Další způsob je použití technologie LiveConnect, která je zaměřená na implementaci balíků v jazyce Java. Javovské balíky se potom převádí na spustitelný kód v JavaSriptu. Na oba přístupy se podíváme dále podrobněji.
3 Platforma Mozilla 24 3.7 Jazyk XBL XBL (extensible Bindings Language) je sesterský jazyk XULu a slouží pro propojování XUL prvků s funkčním kódem a pro přidávání různých vlastností a nových elementů. Je to tedy jeden ze způsobů, jak přidávat XUL prvkům funkčnost. XBL je značkovací jazyk odvozený od XML a obsahuje speciální elementy, pomocí jejichž obsahu se tato funkčnost specifikuje. Základní kostra vypadá následovně: <?xml version="1.0"?> <bindings xmlns="http://www.mozilla.org/xbl"> <binding id="binding1"> <!-- content, property, method and event descriptions go here --> </binding> <binding id="binding2"> <!-- content, property, method and event descriptions go here --> </binding> </bindings> Element bindings je kořenový element dokumentu. Obsahuje potomky elementy binding. Jsou to konkrétní prvky pro propojení určitého XUL elementu a nových generovaných vlastností. Element propojení může být přiřazen jakémukoli XUL elementu. Propojení se přiřazuje konkrétnímu prvku pomocí vlastností CSS. Například můžeme propojit scrollbar s elementem propojení s id= binding1 : scrollbar { -moz-binding: url('chrome://findfile/content/findfile.xml#binding1'); } Přiřazení elementu se provede pomocí CSS vlastnosti moz-binding. Hodnota atributu je URL určitého prvku nebo skupiny prvků. V našem případě jsou všechny elementy scrollbar propojeny s bindingem s konkrétním id. Element binding specifikuje pět typů propojení [7]: 1. Obsah: Podřízené prvky, které jsou přidány k prvku, který je takto vázán. 2. Vlastnosti: atributy, které se přiřazují k elementům. Mohou být zpřístupněny skriptem. 3. Metody: metody, které se přiřazují elementům. Volají se skriptem. 4. Události: jsou to události vyvolané aktivací nějakého prvku. Propojení spočívá v přidání handlenu k události. 5. Styl: volitelné vlastnosti stylu, které může element XBL mít. Každý z těchto typů reprezentuje element s příznačným názvem (content, properties, methods, events, style). Tento element se přidává jako potomek určitého elementu binding. Příklad přidání content ke XUL elementu: <bindings xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <binding id="scrollbarbinding"> <content> <xul:scrollbarbutton type="decrement"/> <xul:slider flex="1"> <xul:thumb/> </xul:slider> <xul:scrollbarbutton type="increment"/> </content>
3 Platforma Mozilla 25 </binding> </bindings> Element scrollbar tak získá další dodatečné vlastnosti. Všechny dodatečné elementy, které se definují v elementu content, musí mít prefix xul:, protože náleží do daného jmenného prostoru XML elementů. Jsou tak rozlišeny XUL elementy a XBL elementy. Scrollbar se tedy výrazně rozšíří: <scrollbar/> se rozšíří na: <scrollbar> <xul:scrollbarbutton type="decrement"/> <xul:slider flex="1"> <xul:thumb/> </xul:slider> <xul:scrollbarbutton type="increment"/> </scrollbar> Obsah přidaný elementem content se nazývá anonymní. Tento typ obsahu není přístupný ze skriptu. 3.7.1 Dědění atributů Pomocí XBL se dá specifikovat XUL elementům, které atributy mají dědit od jejich rodiče. Element inherits určuje, které atributy to mají být. Příklad: <bindings xmlns:xbl="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <xbl:binding id="buttonbinding"> <xbl:content> <xul:button label="ok" xbl:inherits="label"/> </xbl:content> </xbl:binding> V tomto příkladu přidáváme (generujeme) propojovanému XUL prvku element button a říkáme, že má od rodiče dědit atribut label i s jeho hodnotou. Pokud rodič nebude mít atribut label, vytvoří se na buttonu label s implicitní hodnotou OK, jak je stanoveno v XBL. Pokud potřebujeme, aby generované elementy dědily hodnoty jiných atributů do např. atributu label, můžeme hodnotu rodičovského atributu namapovat do jiného atributu. Příklad může být element box s atributem oktitle, k němuž generujeme element button a chceme hodnotu atributu oktitle k elementu button jako hodnotu atributu label. Příklad: XUL: <box class="okcancel" oktitle="ok" canceltitle="cancel" image="happy.png"/> CSS: box.okcancel { -moz-binding: url('chrome://example/skin/example.xml#okcancel'); }
3 Platforma Mozilla 26 XBL: <binding id="okcancel"> <content> <xul:button xbl:inherits="label=oktitle,image"/> <xul:button xbl:inherits="label=canceltitle"/> </content> </binding> Do prvního generovaného elementu button se dědí hodnoty atributu oktitle a image a přiřazují se atributu label. Do druhého elementu button se dědí hodnota atributu canceltitle a přiřazuje se zase k atributu label. Výsledek je potom následující: <box class="okcancel" oktitle="ok" canceltitle="cancel" image="happy.png"> <button label="ok" image="happy.png"/> <button label="cancel"/> </box> 3.7.2 Přidávání vlastností elementům Ke XUL prvkům můžeme vytvářet různé vlastnosti. Tyto vlastnosti mohou být třech typů. Jsou to pole (fields), vlastnosti (property) a metody (methods). Tyto typy jsou definovány elementem implementation, který by měl být potomkem elementu binding. Základní kostra vypadá takto: <binding id="element-name"> <content> -- obsah -- </content> <implementation> <field name="field-name-1"/> <field name="field-name-2"/> <field name="field-name-3"/> <property name="property-name-1"/> <property name="property-name-2"/> <property name="property-name-3"/>... <method name="method-name-1"> -- obsah metod -- </method>... </implementation> </binding> Všechny typy vlastností můžeme specifikovat kódem JavaScriptu. Například vlastnost field umožňuje ukládání hodnoty. V tomto příkladu generujeme náhodná čísla, která se ukládají do pole field s názvem number. XUL: <box id="random-box" class="randomizer"/> <button label="generate"
3 Platforma Mozilla 27 oncommand="document.getelementbyid('randombox').number=math.random();"/> <button label="show" oncommand="alert(document.getelementbyid('randombox').number)"/> XBL: <binding id="randomizer"> <implementation> <field name="number"/> </implementation> </binding> Při kliknutí na element button s názvem Generate se generuje náhodná hodnota a je uložena do pole number. Kliknutím na druhý button potom tohle pole vypíšeme. Vídíme, že pole je přístupné jako vlastnost elementu box s id= random-box přes JavaScript. Pokud místo pole potřebujeme vytvořit vlastnosti (properties) s různými názvy, můžeme je také vygenerovat v XBL. Vlastnosti potom budou přiřazeny objektům reprezentujícím XUL elementy a budou opět přístupné v JavaScriptu. Příklad: <property name="size" onget="return 77;" onset="alert('changed to:'+val); return val;"/> Atributy onget a onset určují co se má provést při modifikaci vlastností a při jejich získání. V tomto příkladě bude mít vlastnost size vždy při získání hodnoty hotnodu 77. Novou hodnotu můžeme přiřadit a obdržet v tomto případě pouze pokud hodnotu modifikujeme. 3.7.3 Přidávání metod elementům K přidávání spustitelného kódu reprezentovaného nějakou JavaScript metodou ke generovaným XUL elementům slouží XBL element method. Tento element je potomkem elementu implementation. Metoda je ovšem definována poměrně netypicky. Název metody i její atributy jsou definovány pomocí XBL elementů stejně jako její tělo. Samotný kód je pak v JavaScriptu. Příklad metody na vrácení maxima ze dvou čísel: XBL: <method name="getmaximum"> <parameter name="num1"/> <parameter name="num2"/> <body> if (num1<=num2) return num2; else return num1; </body> </method> Parametry metod jsou specifikovány v elementu parameter, název metody v atributu name elementu method a tělo metody v elementu body. Aby interpret správně vyhodnotil podmínku if, je potřeba znak < napsat jako entitu <. Metodu potom můžeme zavolat v JavaScript kódu na element, s kterým je svázána. Musíme tuto metodu ale volat až v době, kdy je kompletně sestaven DOM, tedy například po události onload vztahující se k oknu. var element = document.createelement("my_element");
3 Platforma Mozilla 28 element.getmaximum(); 3.7.4 Přidávání obsluhy událostí elementům K tomu, abychom vytvořili obslužný kód k určité události, můžeme použít XBL elementy handlers a handler. Pomocí atributů elementu handler potom obsluhujeme událost. <handlers> <handler event="click" button="0" action="alert('left button pressed');"/> <handler event="mouseup" button="1" action="alert('middle button pressed')"/> <handler event="click" button="2" action="alert('right button pressed');"/> </handlers> Hodnota atributu event určuje název události a hodnota atributu action určuje kód obsluhy události. V tomto případě se při některých událostech myši zobrazí okno s příznačným hlášením. 3.7.5 Dědění v XBL Pokud potřebujeme vygenerovat pomocí XBL více různých elementů s velmi podobnými vlastnostmi, můžeme použít atribut extends u elementu binding. Tím zaručíme, že aktuální binding bude dědit všechny generované elementy a vlastnosti z jiného (v atributu extends definovaného) bindingu. Můžeme tak vytvořit například textbox, který již byl vygenerovaný k nějakému boxu, a přidat mu další vlastnosti. V tomto příkladu se přidává k již vygenerovanému texboxu obsluha události. <binding id="textboxwithhttp" extends="chrome://global/content/bindings/textbox.xml#textbox"> <handlers> <handler event="keypress" keycode="vk_f4"> this.value="http://www"+value; </handler> </handlers> </binding> Ke XUL prvku svázaným s tímto bindingem bude generován textbox s vlastnostmi specifikovanými v bindingu určeném adresou v atributu extends. Navíc bude mít obsluhu události, která při stisku klávesy F4 přidá do textboxu hodnotu http://www. 3.8 Rozhraní XPCOM XPCOM (Cross Platform Component Object Model) je multiplatformní objektový model. Jedná se o vývojové prostředí, které poskytuje následující funkce: Management komponent Abstrakce souborů Předávání objektů mezi platformami Management paměti Mozilla je postavena z kolekce součástí (komponent), z nichž každá plní určité úkoly. Například komponenta pro menu, tlačítko, prvek apod. Komponenty jsou popsány různými definicemi nazývanými rozhraní. [1]
3 Platforma Mozilla 29 Rozhraní v Mozille je definice sad funkcí, které jsou implementovány komponentami. Každá komponenta implementuje funkce, které jsou popsány v rozhraní. Jedna komponenta může implementovat více rozhraní a více komponent může implementovat stejné rozhraní. Vezměme si například komponentu implementující práci se soubory. V JavaScriptu nelze pracovat se soubory, proto musíme napsat rozhraní, tedy funkce a atributy, které budeme implementovat v komponentě. Soubor má vlastnosti jako jméno, datum změny a jeho velikost. Funkce souboru jsou např. přesouvání, kopírování a mazání. Rozhraní pouze popisuje vlastnosti souboru, ne jeho implementaci. Implementace rozhraní je ponechána na komponentu. Komponenta bude mít kód, který určí, jak se zjistí název souboru, datum a velikost. Kromě toho určí, jak se soubor kopíruje, přejmenuje a maže. Z pohledu rozhraní nás nezajímá, jak jej komponenta implementuje. Zajímá nás pouze, pokud jej implementuje správně. Samozřejmě implementace se mohou lišit. Windows a Macintosh verze souboru komponenty by byly výrazně odlišné. Nicméně, oba implementují stejné rozhraní. V Mozille se rozhraní obvykle pojmenovává s prefixem 'nsi' nebo 'mozi', takže jsou snadno rozpoznatelné jako rozhraní. Například nsisound se používá pro přehrávání zvukových souborů a nsilocalfile se používá pro standardní práci se soubory. Proces volání funkcí rozhraní, kdy se překládají skriptové objekty na nativní, zaručuje jedna z vrstev platformy Mozilla. Tato vrstva se nazývá XPConnect. 3.8.1 XPConnect XPConnect vytváří most mezi JavaScriptem a XPCOM komponenty. XPConnect technologie zabalí nativně sestavené komponenty jako objekty, se kterými je možno pracovat v JavaScriptu. Je to vlastně framework, na němž jsou postaveny tyto skriptovatelné komponenty. Pomocí JavaScriptu a XPConnect můžeme vytvořit instance komponent. XPConnect může být rozšířen o podporu skriptovcích jazyků pro implementaci komponent: PyXPCOM již nabízí podporu pro Python, PerlConnect a plxpcom, poskytuje podporu pro Perl a JavaXPCOM pro implementaci komponent v Javě. Existuje iniciativa přidat podporu pro.net a Ruby ve vrstvě XPConnect. Možnost opakovaně využívat XPCOM komponenty z jádra Gecko a možnost vývoje nových komponent, které běží na různých platformách, umožňuje rychlý vývoj aplikací (rapid aplication development) a vyúsťuje v aplikaci, která je produktivnější a snadněji se udržuje. 3.8.2 Jazyk definice rozhraní IDL IDL Interface Definition Language je jazyk, ve kterém se deklarují potřebné třídy a jejich atributy a metody potřebné v rámci rozhraní mezi JavaScriptem a XPCOM komponentou. Jedná se o přenositelný (na operačním systému a hardwaru nezávislý) jazyk, který se používá pro generování přenositelného kódu a typových knihoven. 3.8.3 Vytváření XPCOM komponent Existují tři kroky při volání XPCOM komponenty: získání komponenty, získání té části komponenty, která implementuje rozhraní, které chceme použít, volání požadované funkce. Po získání komponenty a její části pro požadované rozhraní můžeme volat funkce kolikrát chceme. Řekněme, že chceme přejmenovat soubor. Můžeme použít již definované nsilocalfile rozhraní. Prvním krokem je získání souboru komponenty. Potom získáme samotnou komponentu a její část, která implementuje rozhraní nsilocalfile. Nakonec zavoláme funkce poskytované rozhraním. [7]
3 Platforma Mozilla 30 Mozilla ukládá všechny komponenty ve vlastním registru. Přes tento registr se můžeme na komponenty odkazovat. Pokud tedy potřebujeme komponentu, která implementuje výše zmíněné rozhraní nsilocalfile, odkazujeme se na ni řetězcem '@mozilla.org/file/local;1'. Tento řetězec se nazývá contract ID. Na jiné komponenty se odkazuje podobným způsobem. V JavaScriptu můžeme objekt komponenty získat následujícím příkazem: var afile = Components.classes["@mozilla.org/file/local;1"].createInstance(); Komponenta je uložena v afile proměnné. Třída Components ve výše uvedeném příkladu se odkazuje na obecný objekt, který poskytuje metody potřebné pro práci s komponentami. Zde jsme získali třídu komponenty z atributu classes. Atribut classes je pole všech dostupných komponent. Chceme-li získat jinou složku, stačí nahradit contract ID uvnitř hranatých závorek s contract ID komponenty, kterou chceme použít. Instanci komponenty jsme nakonec získali z createinstance() metody. [7] Nicméně nyní máme jen odkaz na komponentu samotnou. Aby bylo možné volat funkce, musíme získat rozhraní. V tomto případě použijeme rozhraní nsilocalfile. Přidáme tedy další řádek: if (afile) afile.queryinterface(components.interfaces.nsilocalfile); Funkce QueryInterface() slouží k získání konkrétního rozhraní komponenty. Tato funkce má jeden parametr, rozhraní, které chceme získat. Vlastnost interfaces objektu komponenty obsahuje seznam všech rozhraní, která jsou k dispozici. Zde předáváme nsilocalfile rozhraní jako parametr metodě QueryInterface (). Výsledkem je, že afile bude odkaz na část komponenty, která implementuje rozhraní nsilocalfile. Předchozí dva příkazy umožňují vytvořit instanci libovolné XPCOM komponenty. XPCOM rozhraní může dědit od jiného rozhraní. Rozhraní, které dědí od ostatních, má své vlastní funkce i funkce všech rozhraní, od kterých dědí. Všechna rozhraní dědí z topúrovňového rozhraní s názvem nsisupports. To dodává funkci QueryInterface(). Protože rozhraní nsisupports je implementováno všemi komponenty, funkce QueryInterface() je k dispozici v každé komponentě. Pokud zavoláme QueryInterface() na objekt a požadované rozhraní není podporováno, je vyhozena výjimka. Pokud si nejsme jisti, zda je rozhraní podporováno komponentou, můžeme použít operátor instanceof pro kontrolu: var afile = Components.classes["@mozilla.org/file/local;1"].createInstance(); if (afile instanceof Components.interfaces.nsILocalFile){ // ošetření } Jakmile máme referenci na implementované rozhraní, můžeme využívat všechny metody a atributy tohoto rozhraní. Rozhraní nsilocalfile má například následující metody a atributy: initwithpath() inicializace cesty a názvu souboru, leafname název souboru bez adresářové struktury vedoucí k němu, filesize velikost souboru, isdirectory() booleovská hodnota určuje, zda je či není soubor typu adresář, remove(recursive) metoda pro smazání souboru. Pokud je parametr recursive true, budou smazány i vnitřní soubory a podadresáře,
3 Platforma Mozilla 31 copyto(directory,newname) kopírování do souboru s novým názvem (newname) do jiného adresáře (directory). Adresář directory je další komponenta typu nsilocalfile. moveto(directory,newname) to stejné jako kopírování, ale nekopíruje, nýbrž přesouvá soubor. Aby bylo možné smazat soubor, je nejprve nutné přiřadit soubor k nsilocalfile. To provedeme metodou initwithpath(). Potom můžeme zavolat metodu remove(). Následující kód demonstruje tyto dva kroky: var afile = Components.classes["@mozilla.org/file/local;1"].createInstance(); if (afile instanceof Components.interfaces.nsILocalFile){ afile.initwithpath("/mozilla/testfile.txt"); afile.remove(false); } 3.8.4 Speciální XPCOM komponenty Některé XPCOM komponenty slouží ke specifičtějším věcem než běžná rozhraní. Takové komponenty nazýváme XPCOM služby (XPCOM services). Jejich instance nevytváří uživatel, existuje pouze jedna instance. Služby poskytují obecné funkce, pomocí nichž buď získáváme, nebo nastavujeme globální data. Také jimi provádíme operace s jinými objekty. Namísto volání createinstance() se volá getservice() k získání reference na složku služeb. [7] Jedním z takových služeb poskytovaných Mozillou je služba vytváření záložek (bookmarks service). To umožní přidávat záložky do aktuálního seznamu záložek uživatele. Příklad je uveden níže: var bmarks = Components.classes["@mozilla.org/browser/bookmarksservice;1"].getService(); bmarks.queryinterface(components.interfaces.nsibookmarksservice); bmarks.addbookmarkimmediately("http://www.mozilla.org","mozilla",0,null); Nejprve je načtena složka "@mozilla.org/browser/bookmarks-service;1" a samotná služba je umístěna v proměnné bmarks. Pomocí QueryInterface() dostaneme nsibookmarksservice rozhraní. Funkci addbookmarkimmediately() lze použít k přidání stránky do záložek. První dva parametry této funkce jsou URL záložky a její název. Třetí parametr je typ záložky, který je běžně 0. Poslední parametr je kódování dokumentu se záložkou, které může být null. [7] 3.9 Kritika XPCOM XPCOM zesložiťuje objekty pracující mezi jednotlivými platformami. To vede k poměrně velkému zesložitění aplikací využívajících tento přístup. To byl jeden z důvodů, proč se Apple rozhodl vytvořit jádro WebKit (které je používáno v internetovém prohlížeči Safari) nad XPCOM-založeném jádrem Gecko u jejich webového prohlížeče. Gecko vývojáři se v současné době snaží snížit přílišné použití XPCOM v jádře Gecko. Tento proces se označuje jako decomtamination v rámci Mozilly. [19] 3.10 LiveConnect Další technologie, kterou kromě modelu XPCOM můžeme použít pro využití funkcionalit nativního kódu pro XUL aplikaci, je LiveConnect. LiveConnect je orientovaný na jazyk Java a komunikaci mezi objekty JavaScriptu a objekty Javy. Pokud z nějakého důvodu
3 Platforma Mozilla 32 potřebujeme přímo programovací jazyk Java, můžeme použít buď modifikaci XPCOM takzvaný JavaXPCOM, nebo právě LiveConnect. Práce s JavaXPCOM je podobná jako s klasickým XPCOM s komponentami implementovanými v jazyce C++. Hlavní rozdíl mezi těmito dvěma přístupy je v implementaci komponenty JavaXPCOM je implementuje v jazyce Java. Docela jiný přístup používá LiveConnect. LiveConnect je API (programové rozhraní), které poskytuje JavaScriptu možnost volání metod tříd implementovaných v Javě i obráceně (tedy volání metod implementovaných v JavaScript z kódu Javy). V této práci se zaměříme na použití Java objektů v JS. [9] 3.10.1 Java Plug-In Java Plug-In je technologie, která slouží k propojení web prohlížečů s platformou Java. Je to část JRE (Java Runtime Enviroment) zahrnutá v prohlížeči. Prohlížeč tedy může interpretovat bajtový kód Javy. Jedna z vrstev technologie Java Plug-In slouží právě jako rozhraní mezi JavaScriptem a Javou. Tato vrstva implementuje veškeré funkce poskytnuté rozhraním LiveConnect. Java Plug-In tedy přebírá veškerou zodpovědnost za implementaci všech funkcí LiveConnectu. 3.10.2 Wrappery (obálky) Wrapper v JavaScriptu je objekt, který obaluje objekt ze zdrojového jazyka (v našem případě objekt Javy). Při programování v JavaScriptu můžeme pomocí wrapperu přistupovat k metodám a datovým složkám objektů Javy. Na straně Javy jsou JavaScript objekty obaleny v instanci třídy netscape.javascript.jsobject a jsou předány Javě. 3.10.3 Práce s Java objekty v JavaScriptu Při používání Java objektů, polí, tříd nebo balíků v JavaScriptu se vyvolávají speciální objekty. Objekt JavaArray JavaClass JavaObject JavaPackage Tabulka 1: Typy Java objektů Popis Obalené Java pole zpřístupněné z JS. JS reference na Java třídu. Obalený Java objekt zpřístupněný z JS. JS reference na Java balík. Používání některých objektů je velmi intuitivní. Například můžeme vytvořit Java objekt String a přiřadit jeho hodnotu nové proměnné v JS. K jejich vytváření používáme operátor new. var mystring = new java.lang.string("hello world"); Proměnná mystring je objekt typu JavaObject. Můžeme přes ni přistupovat k veřejným datovým složkám a metodám třídy java.lang.string a její nadtřídy java.lang.object. mystring.length(); Můžeme přistupovat i k statickým členům objektu JavaClass. alert(java.lang.integer.max_value);
3 Platforma Mozilla 33 Pokud třída není z balíků java, sun nebo netscape, můžeme ji zpřístupnit přes objekt Packages. Mějme balík s názvem redwood, který obsahuje různé třídy. Pro vytvoření instance třídy HelloWorld v balíku redwood můžeme zavolat konstruktor následovně. var red = new Packages.redwood.HelloWorld(); Pokud jsou třídy součástí výchozího balíku (tedy jejich název není specifikován balíkem), přistupujeme k nim přímo přes něj. Například jestliže je třída HelloWorld zpřístupněna přímo přes proměnnou CLASSPATH a ne přes balík, přistupujeme k ní následovně. var red = new Packages.HelloWorld(); Ke třídám z implicitních balíků java, sun a netscape se dá přistupovat zkráceným názvem bez slova Packges. Pokud potřebujeme Java pole typu Array, pracujeme v JS vlastně s objektem JavaArray, který má podobné atributy a metody jako původní Array. var x = java.lang.reflect.array.newinstance(java.lang.integer, 10); 3.10.4 Konverze datových typů mezi JavaScriptem a Javou Protože Java je striktně typový jazyk a JS slabě typový, převádí se argumenty zadané v JS do příslušných datových typů jazyka Java. Pokud předáváme JS číselné typy metodám Javy jako parametry, pravidla pro převod jsou uvedena v tabulce. Java typ parametr metody double java.lang.double java.lang.object float byte char int long short Pravidla konverze Je předána přesná hodnota bez zaokrouhlení a bez ztráty velikosti či znaménka. NaN je převedeno na NaN. Je vytvořena nová instance java.lang.double. Je předána přesná hodnota bez zaokrouhlení a bez ztráty velikosti nebo znaménka. Hodnoty jsou zaokrouhleny na přesnost float. Hodnoty, které jsou extrémně velké nebo extrémně malé jsou zaokrouhleny na hodnotu plus nekonečno, respektive minus nekonečno. NaN je převedeno na NaN. Hodnoty jsou zaokrouhleny v módu round-to-negative-infinity. Hodnoty, které jsou extrémně malé nebo extrémně velké, vyústí v runtime error. NaN nemůže být převedena a vyústí v runtime error. java.lang.string Hodnoty jsou převedeny na string. Např. 237 je převedeno na 237. boolean 0 a NaN jsou převedeny na false. Jiné hodnoty jsou převedeny na true. Tabulka 2: Převod číselných typů přes LiveConnect [9] Pokud předáváme JS booleovské typy metodám Javy jako parametry, pravidla pro převod jsou uvedena v tabulce.
3 Platforma Mozilla 34 Java typ parametr metody boolean java.lang.boolean java.lang.object Pravidla konverze Všechny hodnoty jsou konvertovány v ekvivalent v Javě. Je vytvořena nová instance java.lang.boolean. java.lang.string Hodnoty jsou převedeny na string. Např. true je převedeno na true a false je převedeno na false. Hodnota true je převedena na 1, false na 0. byte char double float int long short Tabulka 3: Převod booleovských typů přes LiveConnect [9] Pokud předáváme JS string typ metodám Javy jako parametr, pravidla pro převod jsou uvedena v tabulce. Java typ parametr metody java.lang.string java.lang.object byte double float int long short char boolean Pravidla konverze V JS 1.4 jsou hodnoty string převedeny na instanci objektu java.lang.string s kódováním Unicode. V JS 1.3 a nižším jsou hodnoty string převedeny na instanci objektu java.lang.string s kódováním ASCII. Všechny hodnoty jsou převedeny na číselné hodnoty podle standardu ECMA-262. V JS 1.4 jsou jednoznakové stringy převedeny na znaky s kódováním Unicode, všechny ostatní hodnoty jsou převedeny na číslo. V JS 1.3 a nižším jsou všechny hodnoty převedeny na číslo. Prázdný string je převeden na false. Všechny ostatní hodnoty jsou převedeny na true. Tabulka 4: Převod typu string přes LiveConnect [9] Pokud předáváme JS nedefinované hodnoty metodám Javy jako parametr, pravidla pro převod jsou uvedena v tabulce. Java typ parametr metody java.lang.string java.lang.object boolean double float byte char int long short Pravidla konverze Hodnota je převedená na instanci java.lang.string, jejíž hodnota je undefined. Hodnota je převedena na false. Hodnota je převedena na NaN. Hodnota je převedena na 0.
3 Platforma Mozilla 35 Tabulka 5: Převod nedefinovaných hodnot přes LiveConnect [9] Pokud předáváme JS null hodnoty metodám Javy jako parametr, pravidla pro převod jsou uvedena v tabulce. Java typ parametr metody Jakákoli třída nebo interface. byte char double float int long short boolean Pravidla konverze Hodnota je převedena na null. Hodnota je převedena na 0. Hodnota je převedena na false. Tabulka 6: Převod null hodnoty přes LiveConnect [9] Pokud předáváme JS objekt typu JavaArray nebo JavaObject metodám Javy jako parametr, ve většině případů jsou objekty jednoduše rozbaleny. V několika situacích je objekt vynuceně převeden na jiný datový typ (viz tabulka). Java typ parametr metody Třída nebo interface kompatibilního typu s typem rozbaleného objektu. java.lang.string byte char double float int long short boolean Pravidla konverze Objekt je rozbalen. Objekt je rozbalen a je zavolána metoda objektu tostring. Je vytvořena nová instance java.lang.string. Objekt je rozbalen a nastává jedna s následujících situací: Pokud rozbalený objekt má metodu doublevalue, JavaArray nebo JavaObject, je převeden na hodnotu vrácenou touto metodou. Pokud rozbalený objekt tuto metodu nemá, nastává chyba. V JS 1.3 a novějším je objekt rozbalen a nastává jedna z následujících situací: Pokud je objekt null, je převeden na false. Pokud má objekt jakoukoli jinou hodnotu, je převeden na true. V JS 1.2 a starším je objekt rozbalen a nastává jedna z následujících situací: Pokud rozbalený objekt má metodu booleanvalue, JavaArray nebo JavaObject, je převeden na hodnotu vrácenou touto metodou. Pokud rozbalený objekt tuto metodu nemá, nastává chyba. Tabulka 7: Převod objektu typu JavaArray přes LiveConnect [9] Pokud předáváme JS objekt typu JavaClass metodám Javy jako parametr, Java převádí objekt podle pravidel uvedených v tabulce.
3 Platforma Mozilla 36 Java typ parametr metody java.lang.class netscape.javascript.jsobject java.lang.object java.lang.string boolean Tabulka 8: Převod typu JavaClass přes LiveConnect [9] Pravidla konverze Objekt je rozbalen. Objekt typu JavaClass je zabalen do instance třídy netscape.javascript.jsobject. Objekt je rozbalen, je zavolána metoda tostring a objekt reprezentuje návratová hodnota této metody, respektive instance java.lang.string. V JS 1.3 a novějším je objekt rozbalen a nastává jedna z následujících situací: Pokud je objekt null, je převeden na false. Pokud má objekt jakoukoli jinou hodnotu, je převeden na true. V JS 1.2 a starším je objekt rozbalen a nastává jedna z následujících situací: Pokud rozbalený objekt má metodu booleanvalue, JavaArray nebo JavaObject, je převeden na hodnotu vrácenou touto metodou. Pokud rozbalený objekt tuto metodu nemá, nastává chyba. Pokud předáváme jiné JS objekty metodám Javy jako parametr, Java převádí objekt podle pravidel uvedených v tabulce. Java typ parametr metody netscape.javascript.jsobject java.lang.object java.lang.string byte, char, double, float, int, long, short Boolean Tabulka 9: Převod ostatních objektů přes LiveConnect [9] Pravidla konverze Objekt je zabalen do instance třídy netscape.javascript.jsobject. Objekt je rozbalen, je zavolána metoda tostring a objekt reprezentuje návratová hodnota této metody, respektive instance java.lang.string. Objekt je převeden na hodnotu použitím logiky operátoru ToPrimitive popsaným ve standardu ECMA-262. V JS 1.3 a novějším je objekt rozbalen a nastává jedna z následujících situací: Pokud je objekt null, je převeden na false. Pokud má objekt jakoukoli jinou hodnotu, je převeden na true. V JS 1.2 a starším je objekt rozbalen a nastává jedna z následujících situací: Pokud rozbalený objekt má metodu booleanvalue, JavaArray nebo JavaObject, je převeden na hodnotu vrácenou touto metodou. Pokud rozbalený objekt tuto metodu nemá, nastává chyba.
3 Platforma Mozilla 37 3.11 Vytvoření zásuvného modulu do prohlížeče Firefox Nyní si vytvoříme velmi základní modul rozšíření pro prohlížeč Firefox. Přidáme do něj plugin, který způsobí, že se v dolní stavové liště (status bar) vytvoří tlačítko, které vyvolá nové okno s hlášením Hello Word!. Nejprve vytvoříme základní strukturu našeho modulu rozšíření. Vytvoříme například složku C:\extensions\my_extension\ nebo ~/extensions/my_extension/. Do této složky vložíme složku chrome a do ní složku content. V kořenovém adresáři našeho rozšíření, tedy..my_extension/ vytvoříme dva textové soubory. Jeden z nich bude kořenový soubor manifestu chrome.manifest a druhý instalační RDF soubor install.rdf. Z instalačního souboru později Firefox zjistí některé základní informace o modulu rozšíření a registruje tento modul. Oba soubory zatím ponecháme prázdné a vytvoříme ještě soubor pro XUL prvky sample.xul. Tento soubor uložíme do adresáře chrome/content. Nyní bychom měli mít následující adresářovou strukturu [18]: <my_extension>\ install.rdf chrome.manifest chrome\ content\ sample.xul Do souboru install.rdf vložíme následující kód [18]: <?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>helloworld@example.net</em:id> <em:version>1.0</em:version> <em:type>2</em:type> <!-- informace o cílové aplikac, podporované verze firefoxu --> <em:targetapplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minversion>1.5</em:minversion> <em:maxversion>4.0.*</em:maxversion> </Description> </em:targetapplication> <!-- metadata --> <em:name>helloworld</em:name> <em:description>testovací modul rozšiřeni</em:description> <em:creator>vaše jméno</em:creator> <em:homepageurl>http://www.example.com/</em:homepageurl> </Description> </RDF> helloworld@example.net je id modulu rozšíření. Je to e-mailová adresa, která nemusí být platná, slouží zkrátka jako id. <em:type> 2 </ em: typ> hodnota 2 zde znamená, že jde o instalaci rozšíření. Pokud by se mělo nainstalovat grafické téma, byla by zde hodnota 4. {ec8030f7-c20a-464f-9b0e-13a3a9e97384} je id Firefoxu.
3 Platforma Mozilla 38 1.5 nejnižší verze Firefoxu, ve které bude modul rozšíření fungovat. 4.0.* maximální verze Firefoxu, ve které bude modul rozšíření fungovat. * znamená, že bude fungovat na všech verzích 4.0.x. Chceme-li přidat do prohlížeče ovládací tlačítko pro spuštění našeho pluginu, musíme změnit některou část prohlížeče přidáním nebo úpravou widgetů. Prohlížeč má rozhraní specifikované v souboru XUL s názvem browser.xul (firefox/ chrome/browser.jar obsahuje content/browser/browser.xul). V browser.xul najdeme stavový řádek, který vypadá nějak takto: <statusbar id="status-bar">... <statusbarpanel>s... </statusbar> Statusbar je element, kam vložíme naše ovládací tlačítko, abychom mohli spouštět plugin. Tohle se děje za pomocí modulu překrytí pro XUL (tzv. XUL Overlay). Je to technika, která umožňuje zanořovat XUL widgety do sebe v rámci různých aplikací. Vytvoříme tedy soubor overlay.xul a uložíme jej do adresáře chrome/content. Do souboru overlay.xul vložíme následující obsah [18]: <?xml version="1.0"?> <overlay id="sample" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <statusbar id="status-bar"> <statusbarpanel id="my-panel" label="hello, World" /> </statusbar> </overlay> <statusbar> určuje "slučovací bod" v okně prohlížeče. <statusbarpanel> je nový widget, který chceme vložit do slučovacího bodu. Otevřeme soubor manifestu chrome.manifest a vložíme následující kód: content helloworld chrome/content/ overlay chrome://browser/content/browser.xul chrome://sample/content/overla y.xul Na prvním řádku určujeme balík content v rámci aplikace helloworld. Na druhém je specifikace modulu překrytí XUL Overlay, která říká, do kterého XUL souboru se má vložit spouštěč pro plugin. Poslední fáze vytváření pluginu je vytvoření XPI souboru. Tento soubor reprezentuje archiv celé aplikace pro pagin. Archivuje se metodou ZIP. Celou adresářovou strukturu, kterou jsme vytvořili ve složce my_extension, tedy archivujeme metodou ZIP. Vytvoříme tedy soubor helloworld.zip. Příponu.zip změníme na příponu.xpi. Soubor helloworld.xpi přesuneme tažením myši do okna prohlížeče Firefox a pustíme. Ve Firefoxu by se mělo vyvolat dialogové okno o instalaci doplňku. Po instalaci restartujeme Firefox a v dolní stavové liště by se měl objevit ovládací prvek, kterým se vyvolá okno s hlášením Hello world!. Obrázek 4: Příklad pluginu
39 4 Řešení systému pro rezervaci objektů Funkčnost aplikační vrstvy daná XPCOM rozhraním a Java objekty nyní demonstrujeme na jednoduchých aplikacích. Ukážeme si zejména manipulaci s vývojovým prostředím. Jedna z nevýhod tohoto přístupu je, že i k jednoduché aplikaci potřebujeme relativně robustní kód a spoustu souborů, které tvoří jednotlivé programové moduly. V pozdější části využijeme nabytých znalostí pro analýzu rezervačního systému. Abychom mohli používat vlastní funkcionalitu, která není přístupná v již napsaných komponentách a již přístupných rozhraních, musíme sestavit vlastní rozhraní a napsat komponentu k jeho implementaci. Objektový model XPCOM je přístupný v celé řadě jazyků. My se zaměříme na JavaScript a C++. Oba jazyky využívají různé části tohoto objektového modelu. Kód psaný v JavaScriptu se provádí na straně klienta (v prohlížeči) a umožňuje vytvářet XPCOM komponenty, které implementují požadované rozhraní (v našem případě) v jazyce C++. Most mezi JavaScriptem a XPCOM je realizován pomocí programového modulu XPConnect, který je součástí Firefoxu (resp. platformy Mozilla) a používá se v XUL aplikacích. XPCOM komponenta pak poskytuje funkcionalitu. Je to vlastně knihovna funkcí. Podobný princip je použit u vytváření potřebné funkcionality pomocí Java objektu. Zabalením Java tříd do JAR balíku se vytvoří zdroj funkcionality pro JavaScript kód podobně jako dynamická knihovna pro XPCOM komponentu. Na oba přístupy se nyní podíváme prakticky. 4.1 Vlastní XPCOM komponenty Zde vytvoříme vlastní rozhraní a vlastní XPCOM komponentu jako demonstraci výše uvedené teorie. Konfigurace programového vybavení, kterou použujeme v tomto příkladě: Windows 7, Visual C++ Express 2008, Firefox 3.6, Gecko SDK 1.9.2. Pro vývoj aplikace je vhodné použít jako stroj, na kterém aplikace poběží, XULRunner (viz výše) místo Firefoxu. Budeme vytvářet aplikaci, která bude využívat jednoduché rozhraní s jednou metodou. Rozhraní bude obsahovat metodu na vrácení součtu dvou celočíselných hodnot (poté přidáme další metodu na vracení pole). Komponentu nazveme MyComponent a metodu Add. 4.1.1 Vytvoření potřebných souborů Projekt, jehož výstupem bude dynamická knihovna funkcí, budeme vytvářet pomocí několika souborů určujících strukturu programového modulu a jeho vymezení. 4.1.1.1 IDL soubor Náš IDL soubor nazvaný IMyComponent.idl bude tedy obsahovat: #include "nsisupports.idl" [scriptable, uuid(***iuid***)] interface IMyComponent : nsisupports { long Add(in long a, in long b); };
4 Řešení systému pro rezervaci objektů 40 Datový typ long reprezentuje celé číslo a klíčové slovo in znamená, že jde o vstupní parametr. Klíčové slovo out by naopak znamenalo, že jde o výstupní parametr metody. Atributy začínají klíčovým slovem attribute. IUID je jednoznačný identifikátor rozhraní. ***IUID*** samozřejmě nahradíme vlastním id interfacu. Můžeme jej snadno vygenerovat například v nějakém generátoru na webové stránce. 4.1.1.2 Vytvoření hlavičkového souboru interfacu a typelib souboru Abychom mohli naše rozhraní používat v XUL aplikaci (v JS kódu) a abychom měli rozhraní k dispozici pro implementaci (v C++ kódu), musíme vytvořit následující dva soubory. XULRunner potom při vyhledávání rozhraní narazí na soubor.xpt a bude dále vyhledávat implementaci k tomuto rozhraní. Informace o rozhraní budou uloženy v hlavičkovém souboru a souboru typelib. Tyto soubory se vytvoří parsováním IDL souboru. K tomu použijeme xpidl.exe, který je součástí Gecko SDK. Cesta ke Gecko SDK je v našem případě C:\xulrunner-sdk\. Přesuneme se do složky, kde je umístěn náš IDL soubor, a z příkazového řádku spustíme příkazy: C:\xulrunner-sdk\sdk\bin\xpidl.exe -m header -I C:\xulrunner-sdk\idl.\IMyComponent.idl C:\xulrunner-sdk\sdk\bin\xpidl.exe -m typelib -I C:\xulrunner-sdk\idl.\IMyComponent.idl Pokud máme Gecko SDK v jiné složce, změníme cestu ke xpidl.exe. 4.1.1.3 Vytvoření hlavičkového souboru MyComponent.h Nyní máme ve složce s IDL souborem další dva soubory IMyComponent.h a IMyComponent.xpt. Je čas vytvořit hlavičkový soubor s obsahem tříd, metod a atributů naší komponenty implementující rozhraní. Vytvoříme tedy nový soubor MyComponent.h. Vložíme do něj makra na protekci zacyklení includování a na definování CUID komponenty: #ifndef _MY_COMPONENT_H_ #define _MY_COMPONENT_H_ #include "IMyComponent.h" #define MY_COMPONENT_CONTRACTID "@localhost/mycomponent;1" //definice contract ID, viz výše #define MY_COMPONENT_CLASSNAME "A Simple XPCOM Sample" #define MY_COMPONENT_CID ***CUID*** ***CUID*** je to samé IUID jako v IDL souboru ve formátu pro C++(např. { 0 12345678, 0 9abc, 0xdef0, { 0 12, 0 34, 0 56, 0 78, 0 9a, 0xbc, 0xde, 0xf0 } } ). Najdeme ho v souboru IMyComponent.h. Zkopírujme jej tedy do MyComponent.h na místo ***CUID***. Ze souboru IMyComponent.h potom zkopírujeme část kódu mezi /* Header file */ a /* Implementation file */ do MyComponent.h. Změňte všechny výskyty _MYCLASS_ na MyComponent. Tuto změnu provádíte pouze v MyComponent.h, ne v IMyComponent.h. Je to z toho důvodu, že v hlavičkovém souboru interfacu (IMyComponent.h) je název třídy pro implementaci rozhraní vygenerován s obecným názvem (_MYCLASS_). Musíme jej tedy změnit na název naší třídy. Na závěr doplňíme konec protekce. #endif //_MY_COMPONENT_H_
4 Řešení systému pro rezervaci objektů 41 4.1.1.4 Vytvoření implementačního souboru komponenty MyComponent.cpp Vytvoříme soubor pro implementaci třídy specifikované v hlavičce, tedy MyComponent.cpp. Nejprve vložíme příkaz k includování hlavičkového souboru: #include "MyComponent.h" Z hlavičkového souboru souboru IMyComponent.h zkopírujeme část kódu mezi /* Implementation file */ a /* End of implementation class template. */. Opět změníme všechny výskyty _MYCLASS_ na MyComponent. Do metody Add vložíme následující kód: *_retval = a + b; return NS_OK; Potom smažeme: return NS_ERROR_NOT_IMPLEMENTED; 4.1.1.5 Vytvoření souboru s definicemi modulu MyComponentModule.cpp Vytvoříme soubor MyComponentModule.cpp, který bude obsahovat následující kód: #include "nsigenericfactory.h" #include "MyComponent.h" NS_GENERIC_FACTORY_CONSTRUCTOR(MyComponent) static nsmodulecomponentinfo components[] = { { MY_COMPONENT_CLASSNAME, MY_COMPONENT_CID, MY_COMPONENT_CONTRACTID, MyComponentConstructor, } }; NS_IMPL_NSGETMODULE("MyComponentsModule", components) 4.1.2 Build knihovny Nyní máme vytvořené tyto soubory: IMyComponent.h, IMyComponent.idl, IMyComponent.xpt, MyComponent.cpp, MyComponent.h a MyComponentModule.cpp. Vytvoříme projekt ve Visual C++ a do sekce Header files přidáme všechny hlavičkové soubory *.h a do Implementation files všechny implementační soubory *.cpp. Ve vlastnostech projektu Project->Properties nastavíme: Configuration Properties General Configuration Type:.dll C/C++ General Additional Include Directories: C:\xulrunner-sdk\include Preprocessor
4 Řešení systému pro rezervaci objektů 42 Preprocessor Definitions: XP_WIN;XP_WIN32;XPCOM_GLUE_USE_NSPR Linker General Additional Library Directories: C:\xulrunner-sdk\lib Input Additional Dependencies: nspr4.lib;xpcom.lib;xpcomglue_s.lib V případě, že se Gecko SDK nachází v jiné složce, zadáme jinou cestu. Nyní můžeme kód zkompilovat a postavit build knihovny. Pokud překladač nehlásí žádné chyby, měl by se vytvořit soubor MyComponent.dll. 4.1.3 Testování Nyní budeme komponentu využívat v naší aplikaci. Interpret JavaSript kódu, ve kterém bude naše komponenta využívána, používá k načtení rozhraní soubory *.xpt a pro implementované funkce a atributy rozhraní soubor *.dll. Musíme tedy interpretu tyto soubory poskytnout. Pokud chceme spustit aplikaci ve Firefoxu, zkopírujeme do složky C:\Program Files\ Mozilla Firefox \components soubory MyComponent.dll a IMyComponent.xpt. Dále vyhledáme složku profilu uživatele ve Firefoxu C:\Users\<jméno_uživatele>\AppData\Roaming\Mozilla\Firefox\Profiles\xxxxxxx x.default\ v operačním systému Windows7 nebo Windows Vista. Jestliže jsme v operačním systému Windows XP nebo Windows 2000, cílová složka profilu uživatele je C:\ Documents and Settings \<jméno_uživatele>\application Data\Mozilla\Fire fox\profiles\xxxxxxxx.default\. Z této složky smažeme soubory compreg.dat a xpti.dat. Pokud aplikaci spouštíme v XULRunneru, stačí do složky komponentů <název_aplikace>/components okopírovat MyComponent.dll a IMyComponent.xpt. Dále vytvoříme soubor main.xul a v něm XUL prvek button. Kód bude vypadat zhruba takto: <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="style.css" type="text/css"?> <window title="tutorial!" orient="vertical" sizemode="maximized" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <button id="but1" label="add"/> <script type="text/javascript" src="script.js"> </window> Dále vytvoříme soubor script.js. window.onload = function(){ try { const cid = "@localhost/mycomponent;1"; var obj = Components.classes[cid].createInstance(); obj = obj.queryinterface(components.interfaces.imycomponent); } catch (err) { alert(err); return; } var but1 = document.getelementbyid("but1"); but1.onclick = function MyComponentTestAdd(){ var res = obj.add(3, 4); alert('sčítám 3+4. Výsledek ' + res + '.'); }
4 Řešení systému pro rezervaci objektů 43 } Soubory main.xul a skript.js musí být ve stejné složce. Pokud používáme XULRunner, okopírujeme je do složky \nazev_aplikace\chrome\content. Potom main.xul otevřeme ve Firefoxu (nebo spusťíme aplikaci v XULRunneru). Po stisku tlačítka Add by se mělo zobrazit hlášení s výsledkem součtu dvou čísel. 4.1.4 Vrácení pole hodnot Pokud budeme potřebovat vytvořit složitější aplikaci, funkce na součet dvou čísel nám sotva bude stačit. Podíváme se tedy na to, jak vrátit homogenní pole hodnot. Do našeho IDL souboru přidáme červeně zvýrazněné řádky: #include "nsisupports.idl" #include "nsiarray.idl" [scriptable, uuid(***iuid***)] interface IMyComponent : nsisupports { long Add(in long a, in long b); nsiarray GetString(); }; Zahrnutím souboru nsiarray.idl zajistíme podporu rozhraní nsiarray, které umožňuje používat speciální pole, jež bude přístupné jak v XPCOM komponentě, tak i v JavaScript calleru. Funkce GetString() bude tedy vracet datový typ nsiarray. Nyní vytvoříme soubory IMyComponent.xpt a IMyComponent.h úplně stejným způsobem jako v předchozím případě, tedy přikazy: C:\xulrunner-sdk\sdk\bin\xpidl.exe -m header -I C:\xulrunner-sdk\idl.\IMyComponent.idl C:\xulrunner-sdk\sdk\bin\xpidl.exe -m typelib -I C:\xulrunner-sdk\idl.\IMyComponent.idl Ze souboru IMyComponent.h okopírujeme následující část kódu do MyComponent.cpp: NS_IMETHODIMP _MYCLASS_::GetString(nsIArray **_retval NS_OUTPARAM) { return NS_ERROR_NOT_IMPLEMENTED; } _MYCLASS_ nahradíme opět MyComponent a NS_ERROR_NOT_IMPLEMENTED nahradíme NS_OK. Dále vložíme do implementačního souboru MyComponent.cpp zvýrazněnou část kódu: nejprve zahrneme knihovny: #include "nsmemory.h" #include "nsstringapi.h" #include "nscomptr.h" #include "nsimutablearray.h" #include "nscomponentmanagerutils.h" #include <nsisupportsprimitives.h> #include <vector> using namespace std; a do metody GetString:
4 Řešení systému pro rezervaci objektů 44 NS_IMETHODIMP MyComponent::GetString(nsIArray **_retval NS_OUTPARAM) { vector<string> vect; vect.push_back("value1"); vect.push_back("value2"); vect.push_back("value3"); vect.push_back("value4"); vect.push_back("value5"); nsresult rv = NS_OK; nscomptr<nsimutablearray>mymutablearray=do_createinstance("@mozilla.o rg/array;1"); &rv); for(unsigned int i=0;i<vect.size();i++) { nscomptr<nsisupportscstring> strarg; strarg = do_createinstance("@mozilla.org/supports-cstring;1", NS_ENSURE_TRUE(strArg, NS_ERROR_FAILURE); strarg->setdata(nscstring((char *)vect[i].c_str())); } rv = mymutablearray->appendelement(strarg, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); } *_retval = mymutablearray; NS_ADDREF(*_retval); return NS_OK; Protože do pole nsiarray nejde přímo zapisovat, vytvořili jsme si měnitelné (mutable) pole nsimutablearray. Nejprve jsme vytvořili pole stringů arr, jehož hodnoty bychom chtěli pomocí této funkce vrátit, potom ukazatel na pole mymutablearray. Následně jsme v cyklu for pro každou položku stringového pole arr vytvořili ukazatel (strarg) na speciální stringovou proměnnou typu nsisupportscstring. Pomocí metody SetData jsme přiřadili do této proměnné hodnotu z našeho pole arr a potom jsme ji přidali na konec pole mymutablearray. Celé pole jsme přiřadili návratové hodnotě funkce. Nyní můžeme knihovnu zkompilovat. Teď se podíváme, jak zpracovat pole v JavaScript calleru. Do souboru main.xul vložme červeně zvýrazněný kód: <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="style.css" type="text/css"?> <window title="tutorial!" orient="vertical" sizemode="maximized" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <button id="but1" label="add"/> <button id="but2" label="show array"/> <script type="text/javascript" src="script.js"/> </window> a do souboru script.js: window.onload = function(){ try { const cid = "@localhost/mycomponent;1"; var obj = Components.classes[cid].createInstance();
4 Řešení systému pro rezervaci objektů 45 obj = obj.queryinterface(components.interfaces.imycomponent); } catch (err) { alert(err); return; } var but1 = document.getelementbyid("but1"); but1.onclick = function MyComponentTestAdd(){ var res = obj.add(3, 4); alert('sčítám 3+4. Výsledek ' + res + '.'); } var but2 = document.getelementbyid("but2"); but2.onclick = function MyComponentTestArray() { var arr = new Array(); var nsarr = obj.getstring(); var enumerate = nsarr.enumerate(); var i=0; while(enumerate.hasmoreelements()){ arr[i]=enumerate.getnext().queryinterface(components.interfaces.nsisupports CString).data; i++; } for(i=0; i<arr.length; i++){ alert(arr[i]); } } } Nyní opět okopírujeme MyComponent.dll a IMyComponent.xpt soubory jako v předchozím případě (do C:\Program Files\Mozilla Firefox\components, pokud používáme XULRunner do <název_aplikace>\components naší aplikace), spustíme main.xul ve Firefoxu (nebo XULRrunneru) a po kliknutí na tlačítko Show array by se mělo zobrazit 5 po sobě následujících vyskakovacích oken s příslušnými stringovými hodnotami. Pole nsarr v tomto případě reprezentuje pole typu nsiarray vrácené z metody GetString(). Pomocí funkce enumerate() vytvoříme strukturu, která se dá procházet. V cyklu while potom pro každý následující prvek vytváříme rozhraní nsisupportscstring a pomocí atributu data získáváme stringovou hodnotu složky pole. Tu pak přiřazujeme do předpřipraveného pole arr. Celé pole potom procházíme cyklem for a zobrazujeme uživateli. 4.2 Práce s vlastním Java objektem v JavaScriptu Pokud chceme používat metody vlastního Java objektu v JS kódu, použijeme následující přístup. Nejprve vytvoříme JAR archiv se třídami, které budeme používat, a okopírujeme jej do složky s naší XUL aplikací. V JS kódu potom budeme potřebovat balík třetí strany, abychom mohli používat neomezeně všechny funkce a možnosti programovacího jazyka Java. Standardně totiž LiveConnect vytváří objekty typu JavaObject ve striktním režimu, kde nejsou podporovány například práce se soubory, JDBC drivery apod. Stáhneme tedy balík javafirefoxextensionutils.jar z adresy http://simile.mit.edu/repository/javafirefox-extension/tools/javafirefoxextensionutils.jar. Tento balík umožní nastavit všem našim vlastním JAR archivům úplná práva v rámci funkčnosti Javy. Nejjednodušší postup, jak vytvořit vlastní Java objekt v JS a používat jeho metody, je tedy následující. 1. Vytvoříme funkci pro získání řetězce reprezentujícího cestu k výchozí složce naší aplikace.
4 Řešení systému pro rezervaci objektů 46 function getapppath(appname) { var chromeregistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"].getService(Components.interfaces.nsIChromeRegistry); var uri = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURI); uri.spec = "chrome://" + appname + "/content/"; var path = chromeregistry.convertchromeurl(uri); if (typeof(path) == "object") { path = path.spec; } path = path.substring(0, path.indexof("/chrome/") + 1); } return path; 2. Vytvoříme funkci pro nastavení plných práv pro JAR archivy. function policyadd (loader, urls) { try { var str = 'edu.mit.simile.javafirefoxextensionutils.urlsetpolicy'; var policyclass = java.lang.class.forname( str, true, loader ); var policy = policyclass.newinstance(); policy.setouterpolicy(java.security.policy.getpolicy()); java.security.policy.setpolicy(policy); policy.addpermission(new java.security.allpermission()); for (var j=0; j < urls.length; j++) { policy.addurl(urls[j]); } alert("sdcs"); }catch(e) { alert(e+'::'+e.linenumber); } } 3. Získáme cestu pro JAR archivy používané v JS. var classloaderjarpath = getapppath('myapp') + "/java/javafirefoxextensionutils.jar"; var myjarpath = getapppath('myapp') + "/java/myjar.jar"; 4. Vytvoříme pole, které bude obsahovat URL adresy JAR archivů určené cestou k nim. Pole bude obsahovat objekty typu JavaObject, tedy zabalené java.net.url. var urlarray = []; urlarray[0] = new java.net.url(myjarpath); urlarray[1] = new java.net.url(classloaderjarpath);
4 Řešení systému pro rezervaci objektů 47 5. Vytvoříme instanci třídy URLClassLoader, která slouží k načtení tříd z JAR archivů z pole urlarray. Instance se vytváří pomocí metody newinstance(url[] urls). try{ var cl = java.net.urlclassloader.newinstance(urlarray); } catch(e){ alert(e) } 6. Nastavíme všem JAR archivům práva a vytvoříme referenci na námi definovanou třídu z URLClassLoaderu za pomoci třídy Class a metody forname(string classname). policyadd(cl, urlarray); var aclass = java.lang.class.forname("cz.mendelu.pef.demo.xuldemo", true, cl); 7. Z reference na třídu následně vytvoříme instanci třídy. var inst = aclass.newinstance(); 8. Nyní můžeme instanci používat jako každý jiný objekt typu JavaObject, tedy konverze mezi datovými typy JS a Javy budou probíhat podle tabulek výše. var returnvalue = inst.methodname(parameters ); 4.2.1 Bližší pohled na nastavení práv pro JRE Výše uvedená funkce policyadd používá metody třídy URLSetPolicy z JAR archivu javafirefoxextensionutils.jar. Nyní se na tuto funkci podíváme blíže. Objekt třídy Policy získáme metodou java.security.policy.getpolicy(). Abstraktní třída Policy reprezentuje systém bezpečnostních práv pro prostředí Java. Specifikuje, která povolení jsou k dispozici. Bezpečnostní práva získáme z podtřídy třídy Policy (v našem případě právě URLSetPolicy), která implementuje metody její metody. Metoda setpolicy(policy p) zkontroluje, zda je vhodné nastavit bezpečnostní práva, a potom pomocí metody addpermission(permission permission) přiřadíme nová přístupová práva. Typ přístupových práv je specifikován parametrem metody addpermission(permission permission). var policy = policyclass.newinstance(); policy.setouterpolicy(java.security.policy.getpolicy()); java.security.policy.setpolicy(policy); policy.addpermission(new java.security.allpermission()); Poslední krok je specifikace JAR archivů, pro které mají být práva nastavena. To provedeme cyklem for, ve kterém se volá metoda addurl(url url). Tato metoda přebírá v parametru URL, který máme uložené v poli urls. for (var j=0; j < urls.length; j++) { policy.addurl(urls[j]); }
4 Řešení systému pro rezervaci objektů 48 4.3 Aplikace Rezervační systém Všechny dosud zmíněné poznatky se dají využít na stavbu obrovské škály aplikací. Abychom ukázali, jak jednotlivé části platformy spolupracují dohromady, vytvoříme poměrně jednoduchou aplikaci s názvem Rezervační systém. Podstatou aplikace bude, aby uživatel mohl rezervovat vzásadě jakékoli fyzické objekty z reálného světa a potom je používat. Aplikace bude sloužit ke správě rezervací. Aplikace bude běžet samozřejmě na platformě Mozilla. 4.3.1 Neformální specifikace Jak již bylo řečeno, hlavním cílem aplikace je poskytnout uživateli rozhraní k rezervaci nějakého objektu. Pod pojmem uskutečnění rezervace si představujeme výběr nějakého objektu uživatelem, zadání času rezervace a následné potvrzení. Uživatel musí být registrovaný v databázi, aby jej bylo možné jednoznačně identifikovat a přiřadit jej ke konkrétní rezervaci. Uživatel se bude moci přihlásit svým přihlašovacím jménem a heslem. Pokud nebude při prvním použití aplikace zaregistrovaný, bude mít možnost rychlé registrace. V registračním formuláři budou následující položky (z nichž jsou barevně označeny povinné položky): přihlašovací jméno (login), jméno, příjmení, heslo, potvrzení hesla, e-mail, ulice + číslo orientační, město. Pokud uživatel nezadá některé z povinných položek, bude vyzván k jejich opětovnému zadání. Jakmile uživatel potvrdí registraci nebo se přihlásí standardním způsobem, bude přesměrován na hlavní stránku s možnostmi aplikace. Hlavní strana bude sloužit jako rozcestník, aby uživatel měl přehled o všem, co je možné v aplikaci provádět. Hlavní rozložení aplikace budou tvořit 3 okna, mezi kterými se bude moci uživatel přepínat pomocí navigační lišty. První okno bude sloužit pro informace o již zarezervovaných objektech přihlášeným uživatelem. Bude to tedy jakýsi výpis rezervací. V tomto výpisu budeme chtít znát: identifikační číslo rezervace, jaký objekt byl zarezervován, odkdy byl zarezervován, dokdy byl zarezervován. V rámci tohoto seznamu bude moci uživatel zvolit rezervaci pro odstranění nebo pro upravení. Samotnou akci potom provede nějakým ovládacím prvkem. Před mazáním bude tázán, zda chce skutečně rezervaci smazat. Další z hlavních oken bude sloužit pro zarezervování objektu. Uživatel si nejprve zvolí ze seznamu nabízených objektů, zadá odkdy a dokdy chce tento objekt rezervovat, a nakonec potvrdí rezervaci. V procesu rezervování se musí zkontrolovat, zda čas rezervace nekoliduje s jinou rezervací. Pokud vše proběhne pořádku, objeví se hlášení o úspěšné rezervaci. Pokud nastane chyba, uživatel bude vyzván k zadání klíčových dat znovu. Toto okno by mělo zároveň sloužit jako okno pro úpravu již hotové rezervace. Pokud tedy uživatel zvolí v seznamu jeho rezervací, že chce některou z nich změnit/upravit, bude přesměrován do tohoto okna s již vyplněnými daty o rezervaci. Tyto data potom bude moci měnit.
4 Řešení systému pro rezervaci objektů 49 Další a poslední okno bude sloužit pro výpis všech rezervací všech objektů. Bude to tedy podobný seznam jako v případě výpisu rezervací uživatele, ale budou tu všechny rezervace v systému. V tomto seznamu budeme chtít tyto položky: objekt rezervace, o čísla rezervací u objektu, o jména rezervovatelů, o data odkdy a dokdy je tento objekt rezervován. Dále se uživatel bude moci odhlásit a bude přesměrován na úvodní stránku. Na podobnou aplikaci by mohla být kladena celá řada dalších požadavků, aby se uživatelům nabídla co největší funkčnost a co největší komfort, ale to není cílem práce. Tato aplikace má demonstrovat, jak se dají dané problémy řešit na platformě Mozilla, a názorně ukázat více variant řešení. 4.3.2 Analýza aplikace Problémy popsané v neformální specifikaci se dají řešit celou řadou vývojových prostředků a programovacích jazyků. My se zaměříme na to, jak se dají tyto problémy řešit v rámci platformy Mozilla. Tato analýza bude tedy analýzou v rámci platformy Mozilla. Analýzu provedeme s ohledem na třívrstvou architekturu, tedy jednotlivé vrstvy aplikace budou prezentační, aplikační a datová. 4.3.3 Prezentační vrstva Z neformální specifikace vyplývá, že bychom měli uživatelům nabídnout příjemné a vysoce funkční uživatelské rozhraní. Jazyk, který je přímo dělaný na popis uživatelských rozhraní, je již v této práci popsán. Je to samozřejmě značkovací jazyk XUL. 1. Úvodní okno V úvodním okně aplikace se bude uživatel přihlašovat. Pomocí XUL tedy vytvoříme jednoduchý přihlašovací dialog. Dialog budou tvořit dvě textová pole pro zadání uživatelského jména a hesla, jejich popisky a dvě ovládací tlačítka. Tlačítka budou sloužit pro přihlášení a pro registraci uživatele. Aby byly popisky textových polí a samotná pole přehledně uspořádány, je vhodné je rozložit přes mřížku. Celou kompozici i s ovládacími tlačítky potom můžeme obalit do skupiny reprezentující celý dialog. Nesmíme zapomínat, že pro příjemné ovládání je vhodné nastavit, aby se přihlášení neprovedlo pouze po stisknutí ovládacího tlačítka pro přihlášení, ale i po stisku klávesy Enter. Je tedy potřeba nastavit příslušnou událost k textovým polím. Při spuštění aplikace by mělo mít první textové pole pro login fokus. Úvodní přihlašovací dialog tedy může vypadat zhruba takto: Obrázek 5: Příklad přihlašovacího dialogu
4 Řešení systému pro rezervaci objektů 50 Technické řešení: Jednotlivé popisky budou samozřejmě reprezentovat XUL elementy label. Přihlašovací tlačítka budou elementy button a textová pole textboxy. Popisky Přihlašovací jméno a Heslo spolu s příslušnými texboxy budou uspořádány v mřížce elementu grid. Aby byla ovládací tlačítka vedle sebe, zahrneme je do horizontálního boxu hbox. Následně celou kompozici obalíme do elementu groupbox, aby bylo jasné, že položky uvnitř spolu souvisí. Vše je samozřejmě zahrnuto v základním kořenovém elementu window. 2. Registrační formulář Pokud se uživatel rozhodne pro registraci do systému, zobrazí se mu registrační formulář. V tomto formuláři zadává 8 výše zmíněných položek potřebných k registraci. Prvky tedy budou podobné jako v přihlašovacím dialogu. Bude zde 8 položek pod sebou, přičemž každá bude popisek a textbox. Popisky a textboxy budou tedy opět uspořádány v mřížce a pod nimi budou dvě ovládací tlačítka. Jedno tlačítko bude sloužit pro potvrzení registrace a další tlačítko pro návrat na úvodní okno pro případ, že by se uživatel rozmyslel. Vše bude opět obaleno do skupiny. Možné rozložení: Obrázek 6: Příklad formuláře pro registraci uživatele Technické řešení: Do elementu grid jako v předchozím případě umístíme elementy label reprezentující popisky a elementy textbox reprezentující jednotlivá textová pole. V horizontálním boxu hbox budou ovládací tlačíka a pod hboxem bude popisek informující o povinných údajích. Celá kompozice se zabalí do skupiny reprezentované elementem groupbox, který se bude nacházet v kořenovém elementu window. 3. Navigační lišta programu Po přihlášení (nebo registraci) se uživatel dostává do hlavní části aplikace. V horní části by se měla nacházet navigační lišta, která bude přepínat mezi jednotlivými hlavními okny. Navigační lištu můžeme vytvořit například pomocí ovládacích tlačítek, které nás po kliknutí přesměrují na požadované okno. Budeme chtít, aby tato lišta byla zobrazena vždy, bez ohledu na to, v jakém okně se uživatel nachází. Pod navigační lištou bude zobrazeno konkrétní okno. Možné řešení:
4 Řešení systému pro rezervaci objektů 51 Obrázek 7: Hlavní okno aplikace Technické řešení: Navigační lišta se bude skládat ze čtyř tlačítek button. Všechny tlačítka budou umístěna v horizontálním boxu hbox. Aby se nad nimi zobrazil element label s popiskem, vložíme hbox a label do vertikálního boxu vbox. Vše pak zahrneme do skupiny groupbox. Aby se nám po kliknutí na tlačítko zobrazil požadovaný obsah pod navigační lištou, budeme potřebovat některý z elementů sloužícíh pro vykreslení velkého obsahu. Tento obsah může být specifikován elementem window v samostatném XUL souboru. Abychom jej zahrnuli do okna s navigační lištou, použijeme element iframe a jeho atribut src. 4. Okno s výpisem rezervací uživatele V tomto okně se má nacházet výpis rezervací uživatele a dvě ovládací tlačítka na upravení a smazání rezervace. Seznam rezervací bude reprezentován nějakou tabulkou se čtyřmi sloupci (číslo rezervace, objekt, odkdy, dokdy). Nadpis sloupců bude hlavička tabulky a zbytek bude tělo tabulky. Pod samotnou tabulkou se budou nacházet ovládací tlačítka. Možné řešení: Obrázek 8: Příklad okna s výpisem rezervací
4 Řešení systému pro rezervaci objektů 52 Technické řešení: V samostatném XUL souboru, na který bude odkazováno z hlavního okna elementem iframe, bude klasický element window, v němž bude umístěna celá kompozice. Nejprve vytvoříme popisek elementem label, aby uživatel věděl, co se zde nachází. Pod popiskem bude tabulka s výpisem. Tabulku se čtyřmi sloupci můžeme vytvořit pomocí elementu tree. Objekt tree bude nehierarchický, tabulkový. Sloupce specifikujeme elementy treecol a jednotlivé položky elementy treeitem. Strom nastavíme tak, aby se zobrazovalo pouze 10 záznamů, a vhodně zvolíme velikost jednotlivých sloupců atributem flex u elementu treecol. Pod strom umístíme hbox s ovládacími tlačítky na smazání a upravení rezervace. 5. Okno pro přidání rezervace Zde se bude nacházet seznam objektů pro rezervování, prvky pro datum rezervace a ovládací tlačítka. Seznam bude obsahovat pouze jeden sloupec název objektu. Pod seznamem budou vstupní textová pole pro datum a popisek vybraného objektu. Tato pole budou speciální elementy, do nichž se budou moci zapsat pouze data. Vedle nich bude ještě vstupní pole pro čas a popisek. Pod nimi bude potvrzovací tlačítko k rezervaci. Možné řešení: Obrázek 9: Příklad okna pro přidání rezervace Technické řešení: Samotný seznam bude reprezentován elementem listbox. V listboxu je jen jeden sloupec s názvem objektu. Při výbětu objektu se vytvoří popisek label pod seznamem. Tento popisek vytvoříme v JavaSriptu, ve kterém bude napsán handler události označení prvku seznamu. Pod popiskem bude skupina groupbox, která bude obsahovat hbox s popisky, elementy pro vstup data datepicker a elementy pro vstup času timepicker. V groupboxu bude ještě potvrzovací tlačítko. 6. Okno s výpisem všech rezervací nad objekty Zde se bude nacházet seznam všech objektů. Tento seznam bude hierarchický bude mít potomky. Každá položka tedy bude skrývat ještě další data. Hlavní položky budou jednotlivé objekty a jejich potomci budou rezervace jednotlivých objektů. Možné řešení:
4 Řešení systému pro rezervaci objektů 53 Obrázek 10: Příklad okna pro výpis všech rezervací Technické řešení: Celou stránku tvoří pouze jeden seznam, tedy hierarchický strom. Tento strom bude mít pouze jeden sloupec, který bude reprezentovat název objektu. Každý název objektu bude v těle stromu jeden element treeitem. K tomuto elementu připojíme ještě element treechildren, ve kterém budou potomci. Potomek bude opět element treeitem, který bude dlouhý řetězec s číslem rezervace, jménem rezervátora a časovou informací odkdy a dokdy. Těchto potomků může mít každý objekt více. 4.3.4 Datová vrstva Datová vrstva určuje způsob, jakým budeme potřebná data ukládat. Buď do fyzického souboru, nebo pomocí SŘBD (Systém Řízení Báze Dat). Moderní aplikace ukládají data pomocí SŘBD do navržené databáze. Zvolíme stejný způsob. V neformální specifikaci je zadáno, že máme ukládat následující položky: Uživatele o přihlašovací jméno (login), o jméno o příjmení, o heslo, o e-mail, o ulice, o město. Objekty o název, o popis. Rezervace o identifikační číslo, o objekt rezervace, o datum a čas rezervace. Entity v databázi tedy můžeme navrhnout podle výše uvedených položek. Budeme mít tedy entity Uživatele, Objekty, Rezervace. K těmto entitám je vhodné přiřadit ještě entitu Typy_objektu. Vztahy budou následující. Uživatel rezervuje nula až více rezervací, přičemž rezervace je rezervována právě jedním uživatelem. Rezervace je přiřazena k právě jednomu
4 Řešení systému pro rezervaci objektů 54 objektu, přičemž objekt může být zarezervován nulakrát až vícekrát. Objekt má právě jeden typ a typ objektu může být přiřazen k více objektům. Z této analýzy vznikne jednoduchý ERD diagram, který můžete najít v příloze práce. Jako SŘBD zvolíme MySQL. 4.3.5 Aplikační vrstva Aplikační vrstva řeší, jakým způsobem se zajistí požadovaná funkčnost aplikace. Jako skriptovací jazyk, který zajišťuje funkčnost XUL elementům, nám poslouží JavaSript. Naše aplikace má ale vyšší nároky, než nám může splnit jazyk JavaScript. V tomto jazyce neexistují žádné objekty a metody pracující s databází. Proto budeme potřebovat část aplikace implementovat v nativním kódu. Část aplikační vrstvy bude tedy implementována jako XPCOM komponenta, nebo jako Java objekt. Aplikační vrstva se nám tak rozdělí na dvě části první část bude implementována v JavaScriptu (kontrola údajů ve formulářích, vytváření XUL prvků pomocí DOM apod.) a druhá část bude implementována v jazyce C++ a jazyce Java (tato část aplikační vrstvy bude sloužit pro přístup k databázi). Objekty XPCOM (jazyka C++) a objekty Javy budou obaleny wrapperem (XPConnect, LiveConnect) a jejich metody budou spouštěny v JavaScriptu. Oba objekty v nativním kódu budou mít vpodstatě stejné metody a atributy (jen drobné odlišnosti u pomocných atributů a pomocných metod) a budou vytvářeny pomocí JavaScriptové třídy vycházející z návrhového vzoru Factory. Stejnojmenná třída Factory tedy bude mít jedinou veřejnou metodu createinstance(string impl), která bude vracet objekt typu specifikovaného parametrem impl. Bude tedy vracet buď objekt XPCOM komponenty, nebo Java objekt. Podstatou tohoto návrhu je to, aby práce s oběma objekty byla v JavaScriptu úplně stejná. Tedy metody, které budou používány v JavaScriptu, budou úplně stejné. Vrstvy aplikace z pohledu programátora budou tedy vypadat zhruba takto: Obrázek 11: Třívrstvá architektura Pokud bychom chtěli znázornit všechny programové moduly, které se na komunikaci mezi vrstvami podílejí, schéma by bylo velmi složité. Na aplikační vrstvě jsou to například XPConnect, LiveConnect, DOM, Java Virtual Machine a spousta dalších. Rozhraní XPCOM, které bude poskytovat metody pro práci s databází nazveme CppService. Komponentu, která jej bude implementovat, pojmenujeme CppServiceImpl. Objekt Java se stejným účelem nazveme JavaServiceImpl. Oba objekty mají stejné metody.
4 Řešení systému pro rezervaci objektů 55 Rozhraní CppService definované v jazyce IDL bude mít tyto metody: CppService long LoginCheck(in string username, in string pass); long RegInsert(in string username, in string psw, in string name, in string surename, in string mail, in string address, in string city, in string phone); void AddQuery(); void AddGetId(out unsigned long count, [array, size_is(count), retval] out long retv); nsiarray GetList(); nsiarray GetInfo(); boolean AddCheck(in long id, in long id_res, in string since, in string to); void AddInsert(in long id_user, in long id_obj, in string since, in string to); void Modify(in long id_user, in long id_obj, in long id_res, in string since, in string to); void PrintQuery(in long id); void PrintGetId(out unsigned long count, [array, size_is(count), retval] out long retv); void GetIdObj(out unsigned long count, [array, size_is(count), retval] out long retv); nsiarray GetObj(); nsiarray GetSince(); nsiarray GetTo(); nsiarray GetName(); void Del(in long id); readonly attribute AString type; Tabulka 10: Popis rozhraní CppService Z tohoto rozhraní vychází i třídní diagram pro Java třídu JavaServiceImpl. Oba implementační objekty mají navíc metody pro práci s databází a pomocné atributy. Třídní diagramy objektů CppServiceImpl a JavaServiceImpl můžete vidět v přílohách. Stručný popis metod rozhraní: LoginCheck Metoda vyhledá v databázi uživatele na základě přihlašovacích údajů. Vrátí identifikační číslo uživatele, pokud existuje. Pokud ne, vrací 0. RegInsert Vloží do databáze informace o novém uživateli na základě parametrů. AddQuery Při přidávání rezervace potřebujeme znát názvy objektů a popis objektů. Tyto informace metoda vloží do pomocných polí, aby byly připravené pro navrácení návratovými metodami AddGetId, GetList a GetInfo. AddGetId Metoda vrací pole id objektů k rezervaci. GetList Metoda vrací pole názvů objektů k rezervaci. GetInfo Metoda vrací pole popisů objektů k rezervaci. AddCheck Metoda kontroluje, zda uživatel zadal datum nové rezervace, které nekoliduje s jinou rezervací daného objektu. AddInsert Vloží do databáze data o nové rezervaci. Modify Změní data o rezervaci v databázi na základě dat změněných uživatelem. PrintQuery Při výpisu rezervací uživatele a výpisu všech rezervací potřebujeme znát id rezervací, názvy objektů a data odkdy je objekt zarezervován, dokdy je rezervován a id objektů. Tyto informace metoda vloží do pomocných polí, aby byly připravené pro navrácení návratovými metodami PrintGetId, GetIdObj, GetObj, GetSince, GetTo, GetName.
4 Řešení systému pro rezervaci objektů 56 PrintGetId Metoda vrací pole id rezervací uživatele. GetIdObj Metoda vrací id objektů. GetObj Metoda vrací názvy objektů pro výpis rezervací uživatele. GetSince Metoda vrací data a časy, odkdy jsou objekty rezervovány pro výpis rezervací uživatele. GetTo Metoda vrací data a časy, dokdy jsou objekty rezervovány pro výpis rezervací uživatele. GetName Metoda vrací názvy objektů pro výpis všech rezervací nad objekty. Del Metoda smaže rezervaci na základě id. Atribut type slouží k rozpoznání implementace objektu. U CppServiceImpl má hodnotu cpp a u JavaServiceImpl hodnotu java. Tyto metody jsou používány v JavaScriptu pro získání dat z databáze potřebných zejména pro stavbu seznamů, stromů a obsluhu ovládacích prvků. Aplikační vrstvu potom implementujeme dle výše uvedených návodů na vytvoření C++ a Java komponent.
5 Diskuse a závěr V této práci byly vytvořeny dva návody na uskutečnění komunikace mezi XUL prvky uživatelského rozhraní a aplikační vrstvou. Zabývají se tím, jak pracovat s XPCOM komponentami a Java objekty pro zpřístupnění dodatečné funkčnosti, která není podporována JavaScriptem. Dále byla napsána aplikace s rezervačním systémem. Oba způsoby komunikace pro aplikační vrstvu umožňjí stejnou práci s vytvořenými objekty a poskytují funkčnost limitovanou pouze vlastními jazyky C++ a Java. Pokud porovnáme složitost objektů CppServiceImpl a JavaServiceImpl, celkem jednoznačně převažuje složitost XPCOM komponenty implementované v C++. Vyplývá to z povahy rozhraní XPCOM. Pro vytvoření komponenty tohoto rozhraní je zapotřebí vlastní objekt jazyka C++ obalit dalším kódem. To děláme z toho důvodu, aby jej bylo možné adaptovat na komunikaci s JavaScriptem. XPCOM ale neumožňuje používat pouze kompilované C++ objekty. Toto rozhraní je totiž navrženo tak, aby podporovalo komunikaci mezi JavaScriptem a objekty dalších (nejen C++) jazyků Java, Perl, Ruby, Python. Sjednocení komunikace mezi těmito jazyky vzniká za cenu zesložitění kódu. Oproti tomu je vrstva LiveConnect zaměřená výhradně na používání Java objektů. Jejich vytváření je pak o mnoho jednodušší. Prvky jazyka XUL se ukázaly jako uživatelsky příjemné a práce s tímto jazykem byla velmi rychlá a snadná. Díky vlastnostem CSS se dá z XUL rozhraní vytvořit uživatelsky velmi zajímavé prostředí. Nejvíce času při vývoji aplikace zabralo sestavování XPCOM komponenty, kde se muselo vytvářet velké množství jednotlivých souborů pro implementaci v jazyce C++. O nastavování kompilátoru nemluvě. Nezkušený nebo nepozorný čtenář se tak může dostat do slepé uličky, z které vede zdlouhavá cesta v podobě hledání chyby. Výkon a praktičnost platformy Mozilla se v některých případech musí vykoupit relativně vyšším úsilím. Jakmile si uživatel platformy osvojí způsob práce, obdrží velmi mocný nástroj pro vývoj svých aplikací. Nyní nic nebrání tomu, abychom dále rozšiřovali aplikaci s rezervačním systémem nebo vytvořili úplně novou. Rezervační systém má nyní jen několik základních funkcí, které byly konstruovány tak, aby ukázaly více možností značkovacího jazyka XUL. Do budoucna je možné přidat další funkčnost k této aplikaci, aby nezůstalo jen u demonstrace technologie. Rezervační systém potom může být šíroce uplatněn. Velmi praktické využití nabízí také zásuvný modul ve webovém prohlížeči Firefox. Uživatel tak získá snadnou kontrolu nad aplikací instalovanou jako zásuvný modul a bude ji moci používat v rámci svého oblíbeného prohlížeče. 57
58 6 Seznam použité literatury [1] MCFARLANE, N. Rapid Application Development with Mozilla. USA: Prentice Hall, 2003. 800 s. ISBN 0-131-42343-6. [2] LOUIS, D. -- MEJZLÍK, P. -- VIRIUS, M. Jazyky C a C++ podle normy ANSI/ISO : Kompletní kapesní průvodce. 1. vyd. Praha: Grada Publishing, 1999. 643 s. ISBN 80-7169-631-5. [3] PECINOVSKÝ, R. -- VIRIUS, M. Objektové programování 1 : Učebnice s příklady v Turbo Pascalu a Borland C++. 1. vyd. Praha: Grada Publishing, 1996. 228 s. ISBN 80-7169-366-9. [4] PECINOVSKÝ, R. Myslíme objektově v jazyku Java : kompletní učebnice pro začátečníky. 2. vyd. Praha: Grada, 2009. 570 s. Myslíme v--. ISBN 978-80-247-2653-3. [5] HOMMEL, Scott, et al. Java 6 : Výukový kurz. [s.l.] : Computer Press, 2007. 536 s. ISBN 978-80-251-1575-6. [6] HEROUT, Pavel. Učebnice jazyka Java. [s.l.] : KOPP, 2008. 381 s. ISBN 978-80-7232-355-5. [7] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. XUL Tutorial. Dostupné z WWW: <https://developer.mozilla.org/en/xul_tutorial>. [8] Mozilla Developer Network [online]. 2011 [cit. 2011-05-17]. Getting started with XULRunner. Dostupné z WWW: <https://developer.mozilla.org/en/getting_started_with_xulrunner>. [9] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. LiveConnect Overview. Dostupné z WWW: <https://developer.mozilla.org/en/core_javascript_1.5_guide/liveconnect_ Overview>. [10] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. Java in Firefox Extensions. Dostupné z WWW: <https://developer.mozilla.org/en/java_in_firefox_extensions>. [11] Nerdlife [online]. 2011 [cit. 2011-05-08]. Building a C++ XPCOM Component in Windows. Dostupné z WWW: <http://nerdlife.net/building-a-c-xpcomcomponent-in-windows/>. [12] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. XPCOM. Dostupné z WWW: <https://developer.mozilla.org/en/xpcom>. [13] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. XPCOM array guide. Dostupné z WWW: <https://developer.mozilla.org/en/xpcom_array_guide>.
6 Seznam použité literatury 59 [14] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. XPConnect. Dostupné z WWW: <https://developer.mozilla.org/en/xpconnect>. [15] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. Mozilla internal string guide. Dostupné z WWW: <https://developer.mozilla.org/en/mozilla_internal_string_guide>. [16] FixUnix [online]. 2011 [cit. 2011-05-08]. How to return string from XPCOM to javascript - Mozilla. Dostupné z WWW: <http://fixunix.com/mozilla/408105-howreturn-string-xpcom-javascript.html>. [17] Praveenmatanam.wordpress.com [online]. 2011 [cit. 2011-05-08]. Returning a JS Array to JavaScript from a C++/JavaScript XPCOM object access through XPConnect. Dostupné z WWW: <http://praveenmatanam.wordpress.com/2007/05/09/returning-a-js-array-tojavascript-from-a-cjavascript-xpcom-object-access-through-xpconnect/>. [18] Mozilla Developer Network [online]. 2011 [cit. 2011-05-08]. Building an Extension. Dostupné z WWW: <https://developer.mozilla.org/en/building_an_extension>. [19] Wikipedia, the free encyclopedia [online]. 2011 [cit. 2011-05-08]. XPCOM. Dostupné z WWW: <http://en.wikipedia.org/wiki/xpcom>. [20] Wikipedia, the free encyclopedia [online]. 2011 [cit. 2011-05-08]. XPConnect. Dostupné z WWW: <http://en.wikipedia.org/wiki/xpconnect>
60 7 Seznam obrázků a tabulek Obrázek 1: Schéma platformy Mozilla [1]... 13 Obrázek 2: Nehierarchický strom se dvěma sloupci... 22 Obrázek 3: Hierarchický strom... 23 Obrázek 4: Příklad pluginu... 38 Obrázek 5: Příklad přihlašovacího dialogu... 49 Obrázek 6: Příklad formuláře pro registraci uživatele... 50 Obrázek 7: Hlavní okno aplikace... 51 Obrázek 8: Příklad okna s výpisem rezervací... 51 Obrázek 9: Příklad okna pro přidání rezervace... 52 Obrázek 10: Příklad okna pro výpis všech rezervací... 53 Obrázek 11: Třívrstvá architektura... 54 Obrázek 12: Ovládací tlačítka, element button... 62 Obrázek 13: Číselný textbox... 64 Obrázek 14: Datepicker typu grid... 64 Obrázek 15: timepicker s hodnotou 12:05:00... 64 Obrázek 16: Listbox se čtyřmi řádky... 65 Obrázek 17: Listbox se dvěma sloupci a třemi řádky... 66 Obrázek 18: Menulist, roletkový seznam... 67 Obrázek 19: Horizontální boxy ve vertikálním boxu... 69 Obrázek 20: Příklad groupboxu... 70 Obrázek 21: Okno s dvěma kartami... 71 Obrázek 22: Rozložení elementů podle mřížky... 72 Obrázek 23: Elementy ifrme v horizontálním boxu odděleny splitterem... 73 Obrázek 24: Nástrojová lišta s tlačítky... 74 Obrázek 25: Menu s popup oknem... 75 Obrázek 26: Menu se zanořeným obsahem... 76 Obrázek 27: Kontextové vyskakovací okno... 76 Obrázek 28: Posouvací box... 77 Obrázek 29: Mapa případů použití... 85 Obrázek 30: Robustní diagram pro přihlášení... 86 Obrázek 31: Robustní diagram pro registraci... 87 Obrázek 32: Robustní diagram pro rezervaci objektu... 88 Obrázek 33: Robustní diagram pro odstranění rezervace... 89 Obrázek 34: Robustní diagram pro všechny rezervace nad objektem... 89 Obrázek 35: Robustní diagram pro kontrolu termínu... 90 Tabulka 1: Typy Java objektů... 32 Tabulka 2: Převod číselných typů přes LiveConnect [9]... 33 Tabulka 3: Převod booleovských typů přes LiveConnect [9]... 34 Tabulka 4: Převod typu string přes LiveConnect [9]... 34 Tabulka 5: Převod nedefinovaných hodnot přes LiveConnect [9]... 35 Tabulka 6: Převod null hodnoty přes LiveConnect [9]... 35 Tabulka 7: Převod objektu typu JavaArray přes LiveConnect [9]... 35 Tabulka 8: Převod typu JavaClass přes LiveConnect [9]... 36 Tabulka 9: Převod ostatních objektů přes LiveConnect [9]... 36 Tabulka 10: Popis rozhraní CppService... 55
61 8 Přílohy 8.1 Popis nejpoužívanějších XUL elementů Jednotlivé elementy jazyka XUL a jejich atributy pro popis uživatelských rozhraní jsou uvedeny v následující části. Okna element window Mějme XUL soubor s následujícím obsahem. <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window id="findfile-window" title="find Files" orient="horizontal" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <!-- dalsi elementy --> </window> Procesní XML instrukce jsou ty, které začínají klauzulí?xml. <?xml version="1.0"?> o indikace začátku XML souboru. <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> o nastavení implicitního stylu zobrazení elementů Element window Je to v podstatě kořenový element většiny XUL souborů. Má několik atributů, některé si popíšeme zde: id="findfile-window" o id je identifikátor elementu, aby na něj bylo možno odkazovat ve skriptech, title="find Files" o title specifikuje text, který se zobrazí na horní liště okna, orient="horizontal" o orient určuje v jakém pořadí se budou vnitřní elementy okna skládat, o hodnota horizontal znamená, že se budou skládat vedle sebe na řádek, horizontálně, xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" o určení jmenného prostoru (namespace) pro element Windows a všechny jeho potomky, o URL adresa není nikdy stáhnuta, Mozilla ji ověřuje vnitřně. Uměle můžeme otevřít okno v JavaScript kódu pomocí příkazu window.open(url,windowname,flags), kde url je cesta ke XUL souboru s oknem, windowname je název okna a flags určují např. délku, výšku apod.
8 Přílohy 62 Ovládací tlačítka element button Element button slouží pro specifikaci akčního tlačítka. V XUL se zapisuje tímto způsobem: <button id="identifier" class="dialog" label="ok" image="images/image.jpg" disabled="true" accesskey="t"/> id je unikátní identifikátor elementu, class určuje třídu elementu pro nastavení stylů, label nastaví elementu popisek, image zobrazí v ploše tlačítka obrázek specifikovaný cestou v URL, disabled pokud je nastaven na true, tlačítko nemůže provést svou funkci a je vybarveno šedivě, accesskey tlačítko provede svou funkci při stisknutí klávesové zkratky nastavené v hodnotě elementu. Příklad: <button label="normal"/> <button label="disabled" disabled="true"/>, Obrázek 12: Ovládací tlačítka, element button Textové, obrázkové elementy elementy label, description, image V jazyce XUL můžeme text zahrnout do okna pouze pomocí elementů k tomu sloužících. Neexistuje žádný smíšený obsah elementu jako v HTML. Element label Slouží pro umístění nějakého doprovodného popisného textu. Do elementu můžeme umístit text dvěma způsoby pomocí atributu value, nebo vložením textu mezi počáteční a koncovou značku elementu. Způsob 1: <label value="this is some text"/> Způsob 2: <label>this is some longer text that will wrap onto several lines.</label> Atribut control slouží k asociování textu s příslušným prvkem, který popisuje. Při kliknutí na asociovaný text dostává popsaný prvek fokus. Např. ovládací tlačítko (button) se s textem asociuje přes hodnoty atributů id a control. Hodnoty musí být stejné. Viz příklad. <label value="click here:" control="open-button"/> <button id="open-button" label="open"/>
8 Přílohy 63 Element description Je velmi podobný elementu label. Hodí se pro delší popisované texty. Je možné vytvořit text přiřazením hodnoty atributu value nebo vložením textu mezi počáteční a koncovou značku. Obecně lze říci, že atribut label je vhodnější pro popis prvků, se kterými má být asociován a element description pro ostatní popisy, protože nepodporuje použití atributu control. Element image Slouží pro zobrazení obrázku v rámci okna. Je velmi podobný elementu img v HTML. URL obrázku můžeme specifikovat pomocí atributu src. <image src="images/banner.jpg"/> Vstupní body elementy textbox, checkbox, radio a radiogroup Tyto elementy jsou velmi podobné vstupním formulářovým prvkům v HTML. V XUL jsou však samostatné. Element textbox Vytváří textové pole pro uživatelský vstup. Může mít např. některé následující atributy: id unikátní identifikátor, class třída pro nastavení CSS stylu, value text, který bude explicitně zobrazen v textovém poli, disabled pokud je nastaveno na true, textbox bude vypnut a nebude se do něj moci zapisovat žádný text, type pokud má nastavenu hodnotu password, skrývá obsah zapisovaného textu, maxlength maximální počet znaků, které se mohou do textboxu zapsat, multiline pokud je nastaven na true, v textboxu můžeme psát text na více řádků. Příklad textboxů označených popisky: <label control="some-text" value="enter some text"/> <textbox id="some-text"/> <label control="some-password" value="enter a password"/> <textbox id="some-password" type="password" maxlength="8"/> Elementy checkbox a radio Element checkbox slouží k označení více možností, u kterých určuje ano/ne. Element radio slouží k výběru jedné z více možností. Atributy: label popisek u elementu, checked u checkboxu, pokud je nastaven na hodnotu checked, checkbox bude zatrhnut (bude vybrán), selected u radio, pokud je nastaven na hodnotu true, aktuální prvek bude vybrán. Element radiogroup Slouží k seskupení elementů radio v jeden celek. Pokud je označen jeden z nich, je zrušeno označení ostatních. Příklad: <radiogroup> <radio id="orange" label="orange"/> <radio id="violet" selected="true" label="violet"/> <radio id="violet" selected="true" label="violet"/> </radiogroup> Atributy společné všem vstupním bodům label, disabled, accesskey mají úplně stejné funkce jako u elementu button.
8 Přílohy 64 Číselné ovládací prvky elementy textbox, scale, datepicker a timepicker Číselné hodnoty můžeme v XUL zadávat pomocí elementů textbox s parametrem type a jeho hodnotou number. Jiné než číselné hodnoty jsou potom ignorovány. Atributy min a max potom můžeme stanovit rozmezí hodnot, které bude textbox přijímat. Atribut increment pak stanoví číselné skoky, po kterých bude skákat hodnota po stisku tlačítka nahoru/dolů. Příklad: <textbox type="number" min="1" max="20" increment="5"/> Obrázek 13: Číselný textbox Element scale Pokud nechceme zadávat číselné hodnoty do textboxu můžeme použít element scale. Hodnotu tak budeme zadávat tažením posuvníku pomocí myši. Atributy min, max a increment mají úplně stejný význam jako u textboxu typu number. Dále atributem orient stanovíme zda bude posuvník orientovaný na šířku (hodnota horizontal ) nebo na výšku (hodnota vertical ). Atributem dir (hodnotou reverse ) stanovíme kterým směrem tažení se bude zvyšovat/snižovat hodnota. Příklady: <scale value="40" min="1" max="50"/> <scale orient="vertical" dir="reverse"/> Element datepicker a timepicker Elementy, jak vyplývá z názvu, slouží k zadávání data a času. Díky nim nemusíme kontrolovat, zda uživatel zadal korektní datum nebo čas. Atributy: value stanoví počáteční hodnotu elementu, pokud je tento atribut vynechán, bude hodnota aktuální datum respektive čas, type u datepickeru, určují, zda má datepicker být jako textbox (hodnota normal ), nebo jako mřížka s posouváním měsíců a vybíráním dnů ve mřížce (hodnota grid ), nebo kombinace obojího (hodnota popup ). Příklad: <datepicker value="2007-02-20" type="grid"/> Obrázek 14: Datepicker typu grid <timepicker value="12:05:00"/> Obrázek 15: timepicker s hodnotou 12:05:00
8 Přílohy 65 Listové seznamy elementy listbox a menulist Listové seznamy slouží pro výpis seznamů o jedné nebo více sloupcích. Uživatel může vybírat hodnotu ze seznamu. Element listbox Jednoduchý listbox s jedním sloupcem se vytváří tak, že mezi počáteční a koncovou značku umístíme vnitřní elementy listitem. Atribut rows určuje velikost listboxu. Příklad listboxu se čtyřmi řádky: <listbox rows="3"> <listitem label="butter Pecan" value="bpecan"/> <listitem label="chocolate Chip" value="chocchip"/> <listitem label="raspberry Ripple" value="raspripple"/> <listitem label="squash Swirl" value="squash"/> </listbox> Obrázek 16: Listbox se čtyřmi řádky Pomocí listboxu můžeme vytvářet také vícesloupcové seznamy. Hlavička se specifikuje elementem liscols a jednolivé položky hlavičky elementem listcol. Vlastní obsah potom elementy listitem, který specifikuje řádek a vnitřním elementem listcell, přičemž hodnota buňky je určena atributem value. Příklad jednoduchého dvousloupcového seznamu se třemi řádky je zde: <listbox> <listcols> <listcol/> <listcol/> </listcols> <listitem> <listcell label="george"/> <listcell label="house Painter"/> </listitem> <listitem> <listcell label="mary Ellen"/> <listcell label="candle Maker"/> </listitem> <listitem> <listcell label="roger"/> <listcell label="swashbuckler"/> </listitem> </listbox> Pokud chceme jinak zobrazit hlavičku tabulky, aby nevypadala jako každý jiný řádek, ale byla zvýrazněná, použijeme elementy listhead a listheader úplně stejně jako elementy listcols a listcol. Pokud chceme určit nadpis sloupce v hlavičce tabulky použijeme u elementu listheader atribut value. Příklad na další straně:
8 Přílohy 66 <listbox> <listhead> <listheader label="name"/> <listheader label="occupation"/> </listhead> <listcols> <listcol/> <listcol flex="1"/> </listcols> <listitem> <listcell label="george"/> <listcell label="house Painter"/> </listitem> <listitem> <listcell label="mary Ellen"/> <listcell label="candle Maker"/> </listitem> <listitem> <listcell label="roger"/> <listcell label="swashbuckler"/> </listitem> </listbox> Obrázek 17: Listbox se dvěma sloupci a třemi řádky Element menulist Pokud potřebujeme jednosloupcový výběrový seznam podobně jako v HTML formulářový prvek select, použijeme XUL element menulist. Samotný element menulist vytváří pouze textbox s tlačítkem na zobrazení možností. Vnitřní element menupopup vytváří okno s možnostmi a vlastní možnosti jsou určeny elementem menuitem a jeho atributem value. Umělý výběr jednoho z prvků provádíme přiřazením atributu selected s hodnotou true. Příklad zde: <menulist label="bus"> <menupopup> <menuitem label="car"/> <menuitem label="taxi"/> <menuitem label="bus" selected="true"/> <menuitem label="train"/> </menupopup> </menulist>
8 Přílohy 67 Obrázek 18: Menulist, roletkový seznam Pokud potřebuje uživatel do menulistu přidávat vlastní možnosti, které nejsou specifikovány v XULu, použijeme u elementu menulist atribut editable s hodnotou true. Průběhové ukazatele element progressmeter Ukazatele průběhu dávají informaci o tom, jaká část z úlohy byla splněna. Jsou dva typy elementu progressmeter: determinate a indeterminate. Typ determinate dává uživateli informaci o tom, kolik času úloha zhruba ještě zabere (vybarvuje se zleva doprava podle toho kolik je z úlohy hotovo). Typ indeterminate pouze informuje o tom, že úloha probíhá (vybarvená část běhá zleva doprava pořád dokola). Typ determinate: Typ indeterminate: Atributy: id unikátní identifikátor, mode hodnota determined znamená, že progressmeter bude typu determinate a hodnota undetermined, že bude typu indeterminate. value u typu determinate, celočíselná hodnota od 0 do 100 znamená počet hotových procent z prováděné úlohy. Příklad: <progressmeter id="identifier" mode="determined" value="50"/> Přidávání HTML elementů do XUL okna Pokud nám z nějakého důvodu nestačí XUL elementy, můžeme použít xhtml elementy. Protože používáme jazyky odvozené z XML je nutné pro xhtml elementy definovat nový jmenný prostor, abychom je odlišily od XUL elementů. xhtml elementy potom budeme zapisovat se zvoleným prefixem. Atribut speficikující jmenný prostor pro xhtml elementy se uvádí pro element window. Zde je příklad: <?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window id="findfile-window" title="find Files" orient="horizontal" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
8 Přílohy 68 Atribut xmlns:html určuje jmenný prostor pro elementy xhtml, které se budou zapisovat s prefixem html. Atribut xmlns pak určuje implicitní jmenný prostor pro elementy XUL. Oba jsou zadány jako atributy elementu window, takže k potomkům elementu window budou specifikované tyto jmenné prostory. Zavádění jmenných prostorů tímto způsobem je nezbytná součást XML aplikací, abychom mohli používat elementy různých jazyků a přitom je od sebe odlišovali. Některé xhtml elementy jako body nebo head nejsou v XUL moc použitelné, nicméně se dají použít. Příklad xhtml kódu, který vytváří obrázek, zaškrtávací políčko a tabulku je zde: <html:img src="banner.jpg"/> <html:input type="checkbox" value="true"/> <html:table> <html:tr> <html:td> A simple table </html:td> </html:tr> </html:table> Mezery mezi elementy element spacer Spacer je element sloužící pro definování rozložení elementů (layout). Přidává do okna prázdné místo. Je to tedy jakýsi prázdný prvek. Má jeden atribut: flex u elementu spacer říká, jak se rozdělí prázdné místo mezi elementy, mezi kterými je spacer vložen. Atribut flex lze přiřadit jakémukoli XUL elementu, nejen spaceru. Funkci má potom stejnou jako u spaceru. Udává jaké místo tento element zabere při aktuální velikosti okna. Příklady: <spacer flex="1"/> V tomto případě se vytvoří prázdné místo mezi elementy, mezi kterými je spacer zahrnut. Hodnota 1 udává, že elementy napravo od spaceru budou v pravé části okna a elementy nalevo v levé části. Spacer pak zabere všechno prázdné místo mezi těmito dvěma skupinami elementů v závislosti na velikosti okna. Představme si tedy dva buttony a spacer s atributem flex= 1 mezi nimi. Pravý button bude vždy napravo, levý nalevo, v závislosti na velikosti okna bude mezi nimi prázdné místo. Buttony budou mít vždy stejnou velikost, se změnou velikosti okna se bude měnit vždy jen velikost prázdného místa (spaceru) mezi nimi. Další příklady: <button label="find" flex="1"/> <button label="cancel" flex="1"/> V tomto případě zabere polovinu místa okna tlačitko s nápisem Find a druhou polovinu tlačítko s nápisem Cancel. Místo, které je v závislosti velikosti okna k dispozici se mezi ně rozdělí 1:1. <button label="find" flex="10"/> <button label="cancel" flex="1"/>
8 Přílohy 69 Obě tlačítka budou měnit velikost se změnou velikosti okna, přičemž tlačítko s hodnotou atributu flex="10" bude zabírat 10ti násobek druhého tlačítka s hodnotu atributu flex="1". <button label="find" flex="2"/> <button label="replace"/> <button label="cancel" flex="4"/> Zde tlačítko s nápisem Replace nebude měnit velikost se změnou velikosti okna. Zbylé dvě tlačítka si rozdělí volné místo v poměru 2:4. <button label="find" flex="145"/> <button label="replace" flex="145"/> Tlačítka si rozdělí volné místo stejně jako v prvním přikladu. Poměr 145:145 je totiž stejný jako 1:1. Pokud nastavíme atributu flex hodnotu 0, je to jako bychom tento atribut úplně vynechali. Box Model elementy hbox a vbox Tzv. Box Model je základní normou pro specifikaci rozložení prvků v XUL aplikaci. S jeho pomocí usměrňujeme všechny XUL elementy do boxů s orientací buď horizontální nebo vertikální. Element hbox Používá se pro vytvoření horizontálně orientovaného boxu. Každý element umístěný uvnitř toho boxu bude zobrazen za předchozím elementem v rovině (na řádku). Element vbox Používá se pro vytvoření vertikálně orientovaného boxu. Každý element umístěný uvnitř toho boxu bude zobrazen pod předchozím elementem (ve sloupci). Příklad: <vbox> <hbox> <label control="login" value="login:"/> <textbox id="login"/> </hbox> <hbox> <label control="pass" value="password:"/> <textbox id="pass"/> </hbox> <button id="ok" label="ok"/> <button id="cancel" label="cancel"/> </vbox> Obrázek 19: Horizontální boxy ve vertikálním boxu
8 Přílohy 70 V příkladu vidíme dva hboxy a dvě tlačítka. Obě části jsou potom obaleny vboxem. V horizontálních boxech jsou elementy zobrazeny vedle sebe a samotné hbox elementy jsou pod sebou ve vertikálním boxu. Skupiny elementů elementy groupbox a radiobox Element groupbox Element groupbox slouží pro seskupení dalších elementů v boxu. Rozdíl oproti např. hboxu nebo vboxu spočívá v tom, že elementy jsou ohraničeny linkou, kterou začíná a končí název groupboxu (určený elementem caption). Tento styl se dá samozřejmě měnit pomocí CSS stylů. Můžeme k nim používat atributy určující rozložení na stránce jako flex nebo orient. Příklad: <groupbox> <caption label="answer"/> <description value="banana"/> <description value="tangerine"/> <description value="phone Booth"/> <description value="kiwi"/> </groupbox> Obrázek 20: Příklad groupboxu Element caption určující název groupboxu může obsahovat dětské elementy např. checkbox. U názvu groupboxu bude tedy ještě zaškrtávací políčko, jehož funkce bude například změnit obsah uvnitř checkboxu (zamknout/odemknout). Těchto možností je samozřejmě mnohem více. Příklad: <groupbox flex="1"> <caption> <checkbox label="enable Backups"/> </caption> <hbox> <label control="dir" value="directory:"/> <textbox id="dir" flex="1"/> </hbox> <checkbox label="compress archived files"/> </groupbox> Element radiogroup Do elementu radiogroup můžeme vložit libovolný element, přičemž tento element slouží pro speciální ovládání elementu radio (z toho vyplývá název). Elementy radio umístěné uvnitř elementu radiogroup budou seskupeny společně i v případě, že některé z nich budou např. v jiném boxu nebo odděleny.
8 Přílohy 71 Vytváření záložek (karet) elementy tabbox, tab, tabtabpanel Záložky (karty) používáme v případě pokud v rámci jednoho okna potřebujeme zobrazit několik záložek s preferencemi. Ve vrchní části je tedy seznam záložek, které zobrazí obsah po kliknutí uživatele. Element tabbox Je to vnější box, který zahrnuje všechny záložky (elementy tabs, tab) a jejich obsah (tabpanels, tabpanel). Elementy tabs, tab Element tabs obsahuje individuální záložky tab. Po kliknutí na určitý tab se zobrazí vlastní obsah. Elementy tabpanels, tabpanel Element tabpanels je box pro jednotlivé tabpanely. Element tabpanel obsahuje tělo záložky určené elementem tab. Pokud existuje více záložek, první tab koresponduje s prvním tabpanelem, druhý s druhým atd. Příklad: <tabbox> <tabs> <tab label="mail"/> <tab label="news"/> </tabs> <tabpanels> <tabpanel id="mailtab"> <checkbox label="automatically check for mail"/> </tabpanel> <tabpanel id="newstab"> <button label="clear News Buffer"/> </tabpanel> </tabpanels> </tabbox> Obrázek 21: Okno s dvěma kartami Element tabs je podobný spíše hboxu, tzn. orientuje jednotlivé dětské elementy horizontálně. Naproti tomu element tabbox funguje spíše jako vbox, tedy orientuje dětské elementy na výšku. Rozložení elementů podle mřížky elementy grid, column a row Rozložení elementů podle mřížky je jeden ze způsobů pozicování XUL elementů. Rozložení je podobné jako rozložení buněk v tabulce HTML. Je určeno elementy column a row. Je tedy dán počet sloupců a řádků. Do této pomyslné tabulky se umístí jednotlivé elementy. Samotní potomci se umisťují buď do elementu row nebo column, přičemž druhý určuje velikost buněk a rozložení. Příklad na další straně:
8 Přílohy 72 <grid flex="1"> <columns> <column flex="2"/> <column flex="1"/> </columns> <rows> <row> <button label="rabbit"/> <button label="elephant"/> </row> <row> <button label="koala"/> <button label="gorilla"/> </row> </rows> </grid> Obrázek 22: Rozložení elementů podle mřížky V tomto příkladu je mřížka 2 sloupce X 2 řádky. Jednotlivé sloupce jsou zahrnuty v elementu columns a řádky v elementu rows. Řádky i sloupce z vnějšku ohraničuje element grid. Zobrazování dalších XUL nebo HTML souborů v okně element iframe Jeden ze způsobů jak vytvořit v jednom okně další okno s jiným obsahem je použití elementu iframe. Obsah, který je v iframe zobrazen je specifikován URL, která se zadává přes atribut src. Iframe může být umístěn kdekoliv v okně a může obsahovat jak XUL, tak HTML obsah. Příklad: <toolbox> <toolbar id="nav-toolbar"> <toolbarbutton label="back"/> <toolbarbutton label="forward"/> <textbox id="urlfield"/> </toolbar> </toolbox> <iframe id="content-body" src="http://www.mozilla.org/index.html" flex="1"/> Tento příklad znázorňuje takový primitivní webový prohlížeč. Obsahuje tlačítka Back a Forward a textové pole pro zadání URL adresy. Tato URL adresa se potom zobrazí pomocí elementu iframe. Další způsob, jak zahrnout jiný obsah do zvláštního okna je použítí elementu browser. Oproti iframe má navíc další funkčnost. Například uchovává historii navštívených URL, což je použitelné právě pro tlačítka Back a Forward. Obecně lze říci, že iframe se hodí pro jednodušší panel v rámci stránky a browser pro složitější interface. Jsou tři typy elementu browser: default (obsah uvnitř elementu má přístup k ostatním XUL prvkům aplikace),
8 Přílohy 73 content (obsah uvnitř elementu nemá přístup k ostatním prvkům) a content-primary (v případě použití více elementů browser, browser označený jako content-primary má obsah, který je přístupný z vnějšku). Tyto typy jsou určeny atributem type. Příklad: <browser src="http://www.mozilla.org" type="content" flex="1"/> Oddělovače obsahu element splitter Pokud potřebujeme změnit velikost pouze části okna a ne celého, použijeme na oddělení obsahu element splitter. Tento element se umístí mezi dvě sekce, jejichž u jejichž obsahu chceme měnit velikost. Pokud je splitter umístěn v horizontálním boxu, umožňuje měnit velikost horizontálně, pokud ve vertikálním boxu, tak vertikálně. Skrytí částí obsahu můžeme docílit buď kliknutím na splitter, nebo uvedením hodnoty do atributu state. Atributy: state Určuje stav splitteru. Hodnota open určuje, že obě části budou zpočátku otevřené. Hodnota collapsed zase, že jedna z částí bude zakrytá, přičemž druhá bude okupovat celou plochu. collapse Říká, která část od splitteru bude skryta, pokud se splitter uvede do stavu collapsed. Hodnota before zaručí skrytí elementu uvedeným před splitterem, after za splitterem a hodnota none znamená, že se po kliknutí na splitter nezakryje žádná část. resizebefore Pokud táhneme se splitterem, elementy vlevo nebo na hoře mění velikost. Tento atribut určuje, které elementy mají změnit velikost. Hodnota closest nastaví elementy bezprostředně vlevo ke změně velikosti. Hodnota farthest naproti tomu nastaví element nejdále vlevo od splitteru (tedy první element v boxu). resizeafter To stejné jako resizebefore s tím rozdílem, že mění velikost elementy napravo od splitteru. Uvnitř splitteru by se měl použít element grippy, který může uživatel použít pro zakrytí elementu. Příklad: <hbox flex="1"> <iframe id="content-1" width="60" height="20" src="w1.html"/> <splitter collapse="before" resizeafter="farthest"> <grippy/> </splitter> <iframe id="content-2" width="60" height="20" src="w2.html"/> <iframe id="content-3" width="60" height="20" src="w3.html"/> <iframe id="content-4" width="60" height="20" src="w4.html"/> </hbox> Obrázek 23: Elementy ifrme v horizontálním boxu odděleny splitterem Zde je splitter umístěn mezi čtyři iframe elementy. Atribut collapse je nastavený na hodnotu before, což znamená, že po kliknutí na element grippy bude zakryt první
8 Přílohy 74 iframe (vlevo). Atribut resizeafter je nastavený na hodnotu farthest, tudíž při táhnutí splitteru se bude měnit velikost čtvrtého iframu (nejvzdálenější vpravo). Nástrojové lišty elementy toolbar, toolbox, toolbutton Toolbar je obvykle umístěn ve vrchní části stránky a obsahuje řadu tlačítek, které provádí běžné funkce. Toolbar může obsahovat jakékoli elementy, obvykle řadu tlačítek orientovanou horizontálně, nebo vertikálně. Pokud používáme více toolbarů, seskupujeme je do elementu toolbox, což je box se specifickými vlastnostmi hodícími se pro právě toolbar. Příklad: <toolbox> <toolbar id="nav-toolbar"> <toolbarbutton label="back"/> <toolbarbutton label="forward"/> </toolbar> </toolbox> V tomto příkladu je uveden jeden toolbar ohraničený boxem toolbox. V toolbaru jsou dvě ovládací tlačítka, toolbar je orientovaný horizontálně. Tlačítko toolbarbutton je v podstatě stejné jako button, jen se jinak vykresluje. Obrázek 24: Nástrojová lišta s tlačítky Menu lišty elementy menu, menubar, menupopup Pod pojmem menu rozumíme panel, který po aktivaci (kliknutí myši) uživatelem zobrazí jednotlivé volby menu. Vytváření menu je podobné jako vytváření přístrojových lišt. Elementy jsou umístěné v boxu (menubar), obvykle obsahuje vlastní menu (menu), které tvoří několik řádků (menuitem), které reprezentují jednotlivé volby. Nejjednodušší je uvést rovnou příklad: <toolbox flex="1"> <menubar id="sample-menubar"> <menu id="file-menu" label="file"> <menupopup id="file-popup"> <menuitem label="new"/> <menuitem label="open"/> <menuitem label="save"/> <menuseparator/> <menuitem label="exit"/> </menupopup> </menu> <menu id="edit-menu" label="edit"> <menupopup id="edit-popup"> <menuitem label="undo"/> <menuitem label="redo"/> </menupopup> </menu> </menubar> </toolbox>
8 Přílohy 75 Obrázek 25: Menu s popup oknem Menubar je kontejner pro jednotlivé panely menu. Element menu reprezentuje pouze název jednoho dílčího menu, které po kliknutí zobrazí jednotlivé volby. Menupopup je box, který se zobrazí při kliknutí na menu. Obsahuje volby menu. Menuitem potom reprezentuje jednotlivé příkazy menu (tlačítka apod.). Menuseparator je oddělovač jednotlivých voleb, obvykle vodorovná čára. Element menu má stejné atributy jako element button avšak obsahuje některé další: disabled Určuje zda je element neaktivní. Hodnoty true a false. accesskey Určuje klávesovou zkratku po jejímž stisknutí se aktivuje menu. Atributy elementu menuitem: disabled, accesskey Stejná funkce jako u elementu menu. acceltext Hodnota tohoto atributu je doprovodný text k určitému prvku menu. type Určuje typ příkazu (tlačítka). Pomocí tohoto atributu můžeme vytvořit checkbox nebo radio jednoduše přiřazením hodnoty checkbox respektive radio. Vytváření zanořených menu (submenu) Zanořené menu vytvoříme jednoduše přidáním elementu menu do obsahu elementu menupopup, tedy mezi jednotivé menuitem elementy. Příklad:... <menupopup id="file-popup"> <menu id="new-menu" label="new"> <menupopup id="new-popup"> <menuitem label="window"/> <menuitem label="message"/> </menupopup> </menu> <menuitem label="open"/> <menuitem label="save"/>...
8 Přílohy 76 Obrázek 26: Menu se zanořeným obsahem Vytváření popup oken Ve XUL můžeme vytvářet tři typy vyskakovacích (popup) oken. Hlavní rozdíl mezi nimi je způsob jejich zobrazení. Prosté vyskakovací okno (menu) (plain popup) se používají jako běžná nabídka, která se zobrazí po stisku levého tlačítka myši. Jsou podobné jako elementy menu v rámci menubar, ale mohou být umístěny kdekoliv. Příkladem může být menu historie navštívených stránek (rozbalovací šipka směrem dolů vedle tlačítek zpět a vpřed ). Kontextové menu kontextová nabídka se zobrazí, když uživatel klikne na kontextové tlačítko, obvykle pravé tlačítko myši (závisí na operačním systému). Okno doplňkových informací okno se zobrazí v případě, když uživatel umístí kurzor myši na element, u kterého se zobrazí doplňkové informace. Obsah popup okna se vytváří v elementu menupopup, který je obstoupen elementem popupset. Abychom zaručili vyskočení okna při aktivaci nějakého prvku, potřebujeme aplikaci sdělit, kde se tak má dít (u kterého elementu) a jaký typ okna se má zobrazit. Toho dosáhneme přiřazením následujících atributů k elementu: popup u elementu s tímto atributem bude vyskakovat prostý popup, context u elementu s tímto atributem bude vyskakovat kontextový popup, tooltip u elementu s tímto atributem bude vyskakovat popup s dopňkovou informací. Asociace mezi prvky potom vzniká tím, že hodnota těchto atributů je shodná s hodnotou atributu id u konkrétního prvku, u kterého se má popup zobrazit. Příklad: <popupset> <menupopup id="clipmenu"> <menuitem label="cut"/> <menuitem label="copy"/> <menuitem label="paste"/> </menupopup> </popupset> <box context="clipmenu"> <label value="context click for menu"/> </box> Obrázek 27: Kontextové vyskakovací okno
8 Přílohy 77 Rolovací menu element arrowscrollbox Pokud potřebujeme do menu přidat velké množství prvků, které by při plném zobrazení zabíralo příliš mnoho místa nebo by prostě kazilo vzhled naší aplikace, použijeme rolovací menu. V rolovacím menu se zobrazí pouze určitý počet prvků z celého výčtu. K ostatním prvkům se potom dostaneme rolováním nahoru/dolů. Toto nám zaručí element arrowscrollbox. Není určený pouze pro rozsáhlé menu, ale může obsáhnout jakýkoli element. Je to vertikálně orientovaný box, prvky se tedy skládají podsebe. Příkad: <arrowscrollbox orient="vertical" flex="1"> <button label="red"/> <button label="blue"/> <button label="green"/> <button label="yellow"/> <button label="orange"/> <button label="silver"/> <button label="lavender"/> <button label="gold"/> <button label="turquoise"/> <button label="peach"/> <button label="maroon"/> <button label="black"/> </arrowscrollbox> Obrázek 28: Posouvací box V tomto příkladě máme arrowscrollbox a v něm umístěny ovládací tlačítka button. Pokud je kurzor myši umístěn v místě boxu, můžeme rolovat jeho obsah.