Opis

Projekt zakończony

Maciej Dudek (4AR) md5@o2.pl

ARD

GEF and Eclipse based editor for ARD and XTT. Evaluation, feasibility, prototype. XTTv2 Editor requirements

Feasibility study, a description how to create such editors with GEF, a prototype editor MS Thesis regarding GEF: Interfejs graficzny do budowy aplikacji komponentowych zapewniający weryfikację semantyczną, ARD+ Editor requirements

Spotkania

Projekt

Source

Sposób uruchomienia

  1. Zaimportuj Ard Editor Diagram oraz Ard Editor Edit jako projekt w Eclipse
  2. Otwórz oba projekty
  3. Kliknij prawym przyciskiem na Ard Editor Diagram:
    1. Run As… → Eclipse Application
  4. W nowo otwartym oknie Eclipse utwórz nowy projekt (wystarczy nawet pusty katalog)
  5. Kliknij New → Examples → My Diagram
  6. Otworzy się edytor. Użytkownik musi podać 2 nazwy plików:
    1. Plik edytora o rozszerzeniu .hml_diagram (odpowiada za rozmieszczenie na ekranie itp)
    2. Plik modelu o rozszerzeniu .hml (w formacie XML)

Sprawozdanie

1. Przygotowanie

1.1 Lektury

Swoją pracę rozpocząłem od lektury następujących prac:

Dalsze kroki to:

  • Uruchomienie programu Varda.
  • Zainstalowanie EMF, GEF, GMF.
  • Uruchomienie przykładowych edytorów: Logic Diagram, Flow Diagram, Shapes Diagram.

1.2 Wyjaśnienie skrótów

Ponieważ skróty EMF, GEF i GMF są do siebie podobne, po krótce wyjaśnię między różnice między tymi frameworkami:

  • EMF - służy do tworzenia modeli, logiki biznesowej. Modele zapisywane są w plikach ecore. Jest możliwa konwersja między modelami w ecore oraz modelem opisanym przy pomocy XSD (XML Schema).
  • GEF - służy do tworzenia edytorów graficznych. Opiera się na bibliotece draw2d, z której czerpie narzędzia do rysowania. Jest dość skomplikowany i trudny w opanowaniu. Daje za to szerokie możliwości. Uwaga, nie mylić z innym GEF, który nie jest projektem Eclipse.
  • GMF - plugin do Eclipse - w stosunku do GEF znacznie ułatwia tworzenie edytorów. Jest niejako graficzną „nakładką” na framework GEF pomagając programiście stworzyć edytor. Można skorzystać z narzędzia dashboard, który jest zaimplementowany jako jeden z widoków w Eclipse. Prowadzi on programistę przez proces tworzenia edytora używając do tego szeregu wizardów i łącząc drobne części ze sobą. Na końcu generowany jest kod edytora w GEF uzupełniony o Runtime GMF. Jednak trudno wykorzystać GMF do zaawansowanych problemów. Dla niestandardowych problemów trzeba edytować kod na własną rękę korzystając z klas GEF. Podsumowując, zastosowanie GMF daje zautomatyzowanie generacji kodu, ale może nie wystarczyć w niestandardowych projektach.

Zatem tworząc aplikację z pewnością użycie wszystkich z nich będzie nieodzowne a ich działanie będzie się przenikało.

2. Pierwsza próba stworzenia edytora

2.1 Użycie definicji DTD i translacja do XSD

Aby skorzystać z możliwości EMF importując model XSD, przekształcono definicję HML.dtd z postaci DTD do postaci XSD. Efekt został przedstawiony poniżej:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="hml">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="type_set"/>
        <xs:element ref="attribute_set"/>
        <xs:element minOccurs="0" ref="property_set"/>
        <xs:element minOccurs="0" ref="tph"/>
        <xs:element minOccurs="0" ref="ard"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="type_set">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="type"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="type">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" ref="desc"/>
        <xs:element ref="domain"/>
      </xs:sequence>
      <xs:attribute name="id" use="required" type="xs:ID"/>
      <xs:attribute name="name" use="required"/>
      <xs:attribute name="base" use="required">
        <xs:simpleType>
          <xs:restriction base="xs:token">
            <xs:enumeration value="integer"/>
            <xs:enumeration value="numeric"/>
            <xs:enumeration value="string"/>
            <xs:enumeration value="bool"/>
            <xs:enumeration value="date"/>
            <xs:enumeration value="time"/>
            <xs:enumeration value="timestamp"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="length"/>
      <xs:attribute name="scale"/>
    </xs:complexType>
  </xs:element>
  <!-- id should begin with 'tpe_...' -->
  <xs:element name="desc" type="xs:string"/>
  <xs:element name="domain">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="range"/>
        <xs:element ref="value"/>
      </xs:choice>
      <xs:attribute name="type">
        <xs:simpleType>
          <xs:restriction base="xs:token">
            <xs:enumeration value="ordered"/>
            <xs:enumeration value="unordered"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
  <xs:element name="range">
    <xs:complexType>
      <xs:attribute name="from" use="required"/>
      <xs:attribute name="to" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="value" type="xs:string"/>
  <xs:element name="attribute_set">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="att"/>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="group"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="att">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" ref="desc"/>
      </xs:sequence>
      <xs:attribute name="id" use="required" type="xs:ID"/>
      <xs:attribute name="type" type="xs:IDREF"/>
      <xs:attribute name="name" use="required"/>
      <xs:attribute name="abbrev"/>
      <xs:attribute name="value" use="required">
        <xs:simpleType>
          <xs:restriction base="xs:token">
            <xs:enumeration value="single"/>
            <xs:enumeration value="multiple"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="class" use="required">
        <xs:simpleType>
          <xs:restriction base="xs:token">
            <xs:enumeration value="ro"/>
            <xs:enumeration value="rw"/>
            <xs:enumeration value="wo"/>
            <xs:enumeration value="state"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
  <!-- id should begin with 'att_...' -->
  <xs:element name="group">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" ref="desc"/>
        <xs:element maxOccurs="unbounded" ref="attref"/>
      </xs:sequence>
      <xs:attribute name="id" use="required" type="xs:ID"/>
      <xs:attribute name="name" use="required"/>
      <xs:attribute name="abbrev"/>
    </xs:complexType>
  </xs:element>
  <!-- id should begin with 'grp_...' -->
  <xs:element name="attref">
    <xs:complexType>
      <xs:attribute name="ref" use="required" type="xs:IDREF"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="property_set">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="property"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="property">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="attref"/>
      </xs:sequence>
      <xs:attribute name="id" use="required" type="xs:ID"/>
    </xs:complexType>
  </xs:element>
  <!-- id should begin with 'prp_...' -->
  <xs:element name="tph">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="trans"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="trans">
    <xs:complexType>
      <xs:attribute name="src" use="required" type="xs:IDREF"/>
      <xs:attribute name="dst" use="required" type="xs:IDREF"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="ard">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="dep"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="dep">
    <xs:complexType>
      <xs:attribute name="independent" use="required" type="xs:IDREF"/>
      <xs:attribute name="dependent" use="required" type="xs:IDREF"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Dokument hml-test.xml poprawnie przechodzi walidację przy użyciu powyższej definicji. Konwersji dokonano przy użyciu programu Trang.

Problem z użyciem powyższej definicji

Powyższa definicja, choć poprawna, okazała się niekompatybilna z frameworkiem GMF. Podstawowe problemy to:

  • Relacja zawierania się - brak bezpośredniego połączenia korzenia z property. W definicji oryginalnej występuje następujące zawieranie: ard → property_set → property. Zgodnie z takim modelem, aby utworzyć property, musielibyśmy tworzyć pośredni element property_set oraz połączenia między nimi. Jest to naturalnie sprzeczne z naszym założeniem.
  • Wybór korzenia - edytor tworzony jest dla konkretnego elementu w modelu. Wybierając korzeń K możemy edytować elementy zawarte w K, ale innych nie. Więc jeśli chcemy mieć możliwość edycji property_set oraz ard to naszym korzeniem musiałby być element hml. Lecz wtedy nasz edytor rozrósłby się jeszcze bardziej - o element ard.
  • Elementy IDREF - korzystanie z elementów IDREF nie uniemożliwia, lecz czyni trudniejszym tworzenie modelu. Trzeba jednak użyć Ecore Annotations.

Dokonano próby utworzenia edytora wszystkich elementów (bez żadnej customizacji) za pomocą pluginu do GMF o nazwie Dynamic GMF. Ten plugin ma w założeniu dać możliwość wygenerowania edytora jedynie przez wybranie pliku xsd. Pojawiał się jednak błąd wewnętrzny programu „Null pointer exception”. Takiego błędu nie było gdy użyłem pliku mindmap.xsd. Sądzę, iż obecność elementów IDREF mogła się do tego przyczynić.

2.2 Inna metodologia tworzenia modeli

Dużo bardziej naturalnym, prostszym i efektywniejszym sposobem jest tworzenie modelu ecore pasującego do GMF. I tak import z XSD następuje do pliku ECORE, na którym później się operuje.

Kolejnym krokiem mogłoby być eksportowanie tego modelu do XSD. W razie potrzeby można by dokonywać konwersji między róznymi definicjami XSD za pomocą szablonów XSLT.

2.3 Własny model

Stworzyłem zatem edytor opierając się o własny model. Model powstał przy pomocy EMF, który następnie wyeksportowałem do formatu XSD.

Nowa wersja Ard.xsd:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:hml="hml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="hml">
  <xsd:element name="Ard" type="hml:Ard"/>
  <xsd:element name="Property" type="hml:Property"/>
  <xsd:element name="Atrybut" type="hml:Atrybut"/>
  <xsd:complexType name="Ard">
    <xsd:sequence>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="property" type="hml:Property"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="Property">
    <xsd:sequence>
      <xsd:element maxOccurs="unbounded" minOccurs="0" name="atrybut" type="hml:Atrybut"/>
    </xsd:sequence>
    <xsd:attribute name="dependant">
      <xsd:simpleType>
        <xsd:list itemType="xsd:anyURI"/>
      </xsd:simpleType>
    </xsd:attribute>
  </xsd:complexType>
  <xsd:complexType name="Atrybut">
    <xsd:attribute name="nazwa"/>
  </xsd:complexType>
</xsd:schema>

Niestety, zawiera on jedynie opis ARD, bez TPH ani XTT.

Poniżej zamieszczono screen z edytora oraz odpowiadający mu plik xml.

2.4 Edytor oparty na własnym modelu

Diagram Ard

hyper.ia.agh.edu.pl_dudekm_zdj_przykladowy_edytor_1.jpg

Wygenerowany plik XML:

<?xml version="1.0" encoding="UTF-8"?>
<hml:Ard xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:hml="hml">
  <property dependant="//@property.1 //@property.2">
    <atrybut nazwa="jeden"/>
    <atrybut nazwa="dwa"/>
  </property>
  <property>
    <atrybut nazwa="trzy"/>
    <atrybut nazwa="cztery"/>
  </property>
  <property>
    <atrybut nazwa="pięć"/>
    <atrybut nazwa="sześć"/>
  </property>
</hml:Ard>

Sprawdzono zgodność pliku xml ze schematem xsd.

Możliwości edytora ważne z punktu widzenia ARD:

  • Dodawanie nowych elementów property.
  • Dodawanie elementów attribute do property.
  • Łączenie elementów property.
  • Zapis do pliku xml.

3. Perspektywy projektu

Jest to wstępny zarys edytora. Docelowy edytor miałby posiadać bogatą funkcjonalność. Dalsze elementy, które należałoby zaimplementować to:

  • Menu kontekstowe zawierające komendy split dla elementów attribute oraz finalize dla elementów property. Custom Actions
  • Utworzenie dwóch dodatkowych warstw: do pierwszej należałyby elementy i połączenia ard bez tph, do drugiego same elementy tph bez ard. Następnie należałoby umożliwić włączanie oraz wyłączanie widoczności warstw. W szczególności obie warstwy mogłyby być widoczne aby widzieć zarówno drzewo TPH jak i ARD.
  • Utworzenie połączenia edytora ARD z edytorem XTT. To połączenie mogłoby przyjąć różną formę:
  1. otwarcia property w edytorze XTT link
  2. edycji XTT poprzez duże zbliżenie (zoom) na sfinalizowany element property.
  • Utworzenie edytora XTT.

4. Wnioski

  • Model warto tworzyć od podstaw w EMF.
  • GEF to potężne narzędzie, lecz trudne w opanowaniu.
  • API GMF oraz GEF zostało w ostatnim czasie uzupełnione o komentarze, lecz nadal jest wiele miejsc, gdzie ich brakuje.
  • Tutoriale są ukierunkowane na kilka zagadnień, w sprawie innych trzeba się pytać na forach dyskusyjnych, lub wręcz pisać do twórców frameworku.

5. Linki

Poniżej zamieszczam wartościowe linki związane z moim projektem:

Instalacja GMF

Nauka

Troubleshooting

Problemy, które napotkałem oraz linki pomocne w ich rozwiązaniu:

Support

Inne

Materiały

pl/miw/miw08_gefardxtt_1.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0