gmf_tutorial7 [GMF Samples And Tutorials]
 

Overview

With GMF, node compartments traditionnaly have list layouts or not layout at all.

The second choice is selected when on want to put the diagram nodes freely in the compartment. The first choice allows to get nodes automatically positionned vertically in the parent node. It is then not possible to move or resize these nodes. For example, we may use this feature if we want to built an UML class diagram editor ; in a class node, two compartments should be inserted vertically, the first accepting attributes, the second accepting operations.

In this tutorial, we will see how to get an horizontal layout which may sometimes fit better one's needs.

The diagram editor will accept one school. In this school, we will be able to add classrooms. Every classroom may accept students. And finally, we will allow students to have friends !

Full code is availabale through :

This tutorial has been built with :

  • Eclipse 3.5.1
  • Graphical Modeling Framework SDK 2.2.1
  • Eclipse Modeling Framework 2.5.0

Model creation

  • Create a new GMF project named School
  • Create a new java package named jfb.examples.gmf.school
  • Create theses java interfaces :
    • Our diagram contains one school :
package jfb.examples.gmf.school.model;
 
/**
 * @model
 */
public interface Diagram {
 
	/**
	 * @model containment="true"
	 */
	School getSchool();
 
}
  • The school has a name and contains classrooms :
package jfb.examples.gmf.school.model;
 
import java.util.List;
 
/**
 * @model
 */
public interface School {
 
	/**
	 * @model
	 */
	String getName();
 
	/**
	 * @model containment="true"
	 */
	List<Classroom> getClassrooms();
 
}
  • Each classroom has a name and contains students :
package jfb.examples.gmf.school.model;
 
import java.util.List;
 
/**
 * @model
 */
public interface Classroom {
 
	/**
	 * @model
	 */
	String getName();
 
 
	/**
	 * @model containment="true"
	 */
	List<Student> getStudents();
 
}
  • Each student has a name and may have some friends (students as well)
package jfb.examples.gmf.school.model;
 
/**
 * @model
 */
public interface Student {
 
	/**
	 * @model
	 */
	String getName();
 
	/**
	 * @model
	 */
	List<Student> getFriends();
 
}
  • Create a new EMF Generator Model named school.genmodel in the model folder (right click on the School project, select New, choose EMF Generator Model)
  • Select the package that you have just created above and click finish
  • Optionnaly, you can generate a visual representation of the model by right clicking on the school.ecore file that has been generated above and by selecting Initialize ecore_diagram diagram file
  • You should get this :

  • In the Dashboard view :
    • select the Domain Gen Model file (school.genmodel)
    • select the Domain Model file (school.ecore)
  • Open the school.genmodel file
  • Right click on the root element of the diagram and select Generate Model Code
  • Right click on the root element of the diagram and select Generate Edit Code
  • Right click on the root element of the diagram and select Generate Editor Code

Tooling definition (diagram palette)

  • Click on the derive label on the left of the Tooling Def Model rectangle of the Dashboard view
  • Choose school.gmftool as file name and click Next
  • Select the Diagram class as Diagram Element and click Next
  • In the Node column, only the following entries must be checked : Classroom, Student (School is not checked because, later in this tutorial, we will make it automatically available when a new diagram is initiated).
  • In the Links column, only the friends : Student entry must be checked
  • You should have :

Graphical definition

  • Click on the derive label on the left of the Graphical Def Model rectangle of the Dashboard view
  • Choose school.gmfgraph as file name and click Next
  • Select the Diagram class as Diagram Element and click Next
  • In the Node column, only the following entries must be checked : Classroom, School, Student
  • In the Links column, only the friends : Student entry must be checked
  • In the Label column, only the following entries must be checked : Classroom.name, School.name, Student.name
  • You should have :

  • Open the school.gmfgraph file
  • Delete the Polyline Decoration StudentFriendsTargetDecoration node
  • Under the Rectangle ClassroomFigure node :
    • Delete the Flow Layout node
    • Add a Boder Layout node
    • Add a Rectangle node and set its name to ClassroomCompartmentFigure
    • Under the Label ClassroomNameFigure, add a Border Layout Data node and set its properties :
      • Alignment=BEGINNING
      • Vertical=true
    • Under the Rectangle ClassroomCompartmentFigure, add a Border Layout Data node and set its properties :
      • Alignment=CENTER
      • Vertical=true
  • Under the Figure Descriptor ClassroomFigure node, add a Child Access and in the property view, select the Rectangle ClassroomCompartmentFigure entry.
  • Under the Rectangle SchoolFigure node :
    • Delete the Flow Layout node
    • Add a Boder Layout node
    • Add a Rectangle node and set its name to SchoolCompartmentFigure
    • Under the Label SchoolNameFigure, add a Border Layout Data node and set its properties :
      • Alignment=BEGINNING
      • Vertical=true
    • Under the Rectangle SchoolCompartmentFigure, add a Border Layout Data node and set its properties :
      • Alignment=CENTER
      • Vertical=true
  • Under the Figure Descriptor SchoolFigure node, add a Child Access and in the property view, select the Rectangle SchoolCompartmentFigure entry.
  • Under the Canvas node :
    • Add a Compartment node and set its properties to :
      • Accessor=Child Access getFigureSchoolCompartmentFigure
      • Figure=Figure Descriptor SchoolFigure
      • Name=SchoolClassroomsCompartment
    • Add another Compartment node and set its properties to :
      • Accessor=Child Access getFigureClassroomCompartmentFigure
      • Figure=Figure Descriptor ClassroomFigure
      • Name=ClassroomStudentsCompartment
  • Save the diagram
  • Re open the school.gmfgraph file (but as Text file (right click on the file, menu Open with > Text Editor
  • Find the xsi:type attribute of the actualFigure node of the ClassroomFigure and set it to gmfgraph:RoundedRectangle :
      <actualFigure
          xsi:type="gmfgraph:RoundedRectangle"
          name="ClassroomFigure">

Mapping model

  • Click on the combine label on the left of the Mapping Model rectangle of the Dashboard view
  • Choose school.gmfmap as file name and click Next
  • Select the Diagram class as Diagram Element and click Next
  • In the Select Diagram Palette wizard page, just click next
  • In the Select Diagram Canvas wizard page, just click next
  • In the Mapping wizard page, remove the Classroom entry from Links zone
  • Click Finish
  • Open the school.gmfmap file generated above
  • Under the Mapping node add a Link Mapping node and set its properties :
    • Target Feature=Student.friends:Student
    • Diagram Link=Connection StudentFriendConnection
    • Tool=Creation Tool Friend
  • Select the Node Mapping <School/School> node and unset its Tool property (later in this tutorial, we will make school automatically available when a new diagram is initiated, a creation tool would be unusefull).
  • Under the Node Mapping <School/School> node :
    • add a Child Reference node and set its Containment Feature property to School.classrooms:Classroom
    • add a Compartment Mapping node and set its properties :
      • Children=Child Reference <classrooms>
      • Compartment=Compartment SchoolClassroomsCompartment (SchoolFigure)
  • Under the Child Reference <classrooms> node, add a Node Mapping node and set its properties :
    • Element=Classroom
    • Diagram Node=Node Classroom (ClassroomFigure)
    • Tool=Creation Tool Classroom
  • Under the Node Mapping <Classroom/Classroom> node :
    • add a Featured Label Mapping and set its properties to :
      • Feature to display=Classroom.name:EString
      • Diagram Label=Diagram Label ClassroomName
    • add a Child Reference node and set its Containment Feature property to Classroom.students:Student
    • add a Compartment Mapping node and set its properties :
      • Children=Child Reference <students>
      • Compartment=Compartment ClassroomStudentsCompartment (ClassroomFigure)
  • Under the Child Reference <students> node, add a Node Mapping node and set its properties :
    • Element=Student
    • Diagram Node=Node Student (StudentFigure)
    • Tool=Creation Tool Student
  • Under the Node Mapping <Student/Student> node, add a Featured Label Mapping and set its properties to :
    • Feature to display=Student.name:EString
    • Diagram Label=Diagram Label StudentName
  • Save the file

Diagram Editor generation

  • Click on the transform label above the Diagram Editor Gen model rectangle of the Dashboard view
  • Open the school.gmfgen file
  • Select the Gen Compartment SchoolSchoolClassroomsCompartmentEditPart node and set the List Layout property to true
  • Select the Gen Compartment ClassroomClassroomStudentsCompartmentEditPart node and set the List Layout property to false
  • Save the file
  • Click on the Generate diagram editor label in the Diagram Editor Gen model rectangle of the Dashboard view

Diagram initialization

At this point, if we launch the diagram editor, we will not be able to create classrooms and students because we have chosen not to add a creation button for the School element.

The following steps will allow to automatically add a new school every time a diagram is created :

  • Edit the jfb.examples.gmf.school.diagram.part.SchoolDiagramEditorUtil java class
  • Modify the createInitialModel method like this (do not forget to add NOT after @generated):
	/**
	 * Create a new instance of domain element associated with canvas.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	private static Diagram createInitialModel() {
		Diagram diagram = SchoolFactory.eINSTANCE.createDiagram();
		School school = SchoolFactory.eINSTANCE.createSchool();
		diagram.setSchool(school);
		return diagram;
	}

As we have no creation tool for our school, we want to prevent it from being removed. To do that :

  • Edit the jfb.examples.gmf.school.diagram.edit.helpers.SchoolEditHelper java class
  • Modify the getDestroyElementCommand method like this (do not forget to add NOT after @generated) ; this will disable the Delete from model popup menu item :
	/**
	 * @generated NOT
	 */
	protected ICommand getDestroyElementCommand(DestroyElementRequest req) {
		// Prevents from removing the figure
		return UnexecutableCommand.INSTANCE;
	}
  • Edit the jfb.examples.gmf.school.diagram.edit.parts.SchoolEditPart java class
  • Modify the createDefaultEditPolicies method like this (do not forget to add NOT after @generated) ; this will disable the delete action when you type on the delete key :
	/**
	 * @generated NOT
	 */
	protected void createDefaultEditPolicies() {
		installEditPolicy(EditPolicyRoles.CREATION_ROLE,
				new CreationEditPolicy());
		super.createDefaultEditPolicies();
		installEditPolicy(EditPolicyRoles.SEMANTIC_ROLE,
				new SchoolItemSemanticEditPolicy());
		installEditPolicy(EditPolicy.LAYOUT_ROLE, createLayoutEditPolicy());
		installEditPolicy(EditPolicy.COMPONENT_ROLE, new ComponentEditPolicy() {
			public Command getCommand(Request request) {
				// If the user presses the delete key, don't delete
				if (request instanceof GroupRequestViaKeyboard 
						&& RequestConstants.REQ_DELETE.equals(request.getType())) {
					return UnexecutableCommand.INSTANCE;
				}
				return super.getCommand(request);
			}
		});
	}

Now we will modify the School layout behavior in order to get vertical classrooms :

  • Edit the jfb.examples.gmf.school.diagram.edit.parts.SchoolSchoolClassroomsCompartmentEditPart java class
  • Modify the createFigure method like this (do not forget to add NOT after @generated):
	/**
	 * @generated NOT
	 */
	public IFigure createFigure() {
		ResizableCompartmentFigure result = (ResizableCompartmentFigure) super
				.createFigure();
		result.setTitleVisibility(false);
		// Fix the margins
		Insets insets = result.getContentPane().getInsets();
		insets.top = 5;
		insets.bottom = 5;
		insets.left = 5;
		insets.right = 5;
		// Layout behavior modification : data must be represented horizontally
		ConstrainedToolbarLayout layoutMgr = (ConstrainedToolbarLayout) result
				.getContentPane().getLayoutManager();
		layoutMgr.setVertical(false);
		layoutMgr.setStretchMajorAxis(true); // uses all the avalaible space
		layoutMgr.setStretchMinorAxis(true); // uses all the avalaible space
		layoutMgr.setSpacing(5);
		return result;
	}

We will also make the default school size bigger than 40×40 :

  • Edit the jfb.examples.gmf.school.diagram.edit.parts.SchoolEditPart java class
  • Modify the createNodePlate method like this (do not forget to add NOT after @generated):
	/**
	 * @generated NOT
	 */
	protected NodeFigure createNodePlate() {
		DefaultSizeNodeFigure result = new DefaultSizeNodeFigure(600, 300);
		return result;
	}

This will allow to use rectilinears edges by default :

  • Edit the jfb.examples.gmf.school.diagram.preferences.DiagramConnectionsPreferencePage java class
  • Add the following method :
	/**
	 * @generated NOT
	 */
	public static void initDefaults(IPreferenceStore preferenceStore) {
		preferenceStore.setDefault(IPreferenceConstants.PREF_LINE_STYLE,
				Routing.RECTILINEAR);
	}

At this point, our diagram has a default : if you click on a classroom, and click again on the classroom's compartment, the compartment is marked as selected. Iy you right click on it, you can select Delete from model. If you select it, the compartment is deleted from the diagram, but after it is not possible to get it back and the contained students are not deleted from the model !

To diable this, we have to :

  • Edit the jfb.examples.gmf.school.diagram.edit.policies.ClassroomClassroomStudentsCompartmentItemSemanticEditPolicy java class
  • Add the following method :
	/**
	 * @generated NOT
	 */
	protected Command getSemanticCommand(IEditCommandRequest request) {
		if (request instanceof DestroyRequest) {
			return null;
		}
		return super.getSemanticCommand(request);
	}

Running the diagram editor

At this point, when running the diagram editor, you should get this result :

Thank you

I hope that this material will be helpful for you. If you want to support it, your help is welcome :

Discussion

Asma, 2010/05/06 16:06

Hi, Thank u for this tutoriel. But i want, if u don't mind to ask a question. In my project, i need to add 2 labels in the same line in a compartment. Is it possible and how to do it? Thank u in advance. Asma

Jean-François Brazeau, 2010/07/07 21:39

Hello,

I think it is possible. If I had to do that, in the EMF I would create 2 objects, the first (the parent object) containing the second (the child object, don't forget to set the containment property to true). In the second object, I would add my two attributes corresponding to the 2 labels that you want to put on the same line. I don't describe the way to get the compartment work as it is already described in the tutorials of this site. In the gmfgraph file, I would remove the Flow layout of the Rectangle figure that corresponds to the child object, I would put a BorderLayout instead and I would a Border Layout Data to each label, the first with the alignment set to BEGINNING, and the second to END….

Hope it helps (if it understandable !….)

Regards,

JFB

Chafik, 2010/05/10 11:26

Hi, Thank you very much for those tutoriels wich are really super helpfull. I am working in a GMF project and i am still beginner, i am searching for a book wich describes the generated Java classes of the plugin. I need also to personnalise the properties view of the generated modeler. Finally i need to add compartment as label and not rectangle ( i tried it but i didnt work :( ) Thank you very much

Jean-François Brazeau, 2010/07/07 21:45

Hi,

I cannot give you any advice on a gook book about GMF. I personnaly found the answers to my problems on the net or by myself after a few hours of hard job !!!! It is true that the documentation available on this technology is not very accessible (that is why I decided to publish these tutorials).

As far as I can see, the personlization the properties view of your modeler is an EMF issue. This is not specific GMF.

I don't exactly understand what you mean when you say that you want to add a compartment as a label. Could you precise it ?

Regards,

JFB

Nageswararao.M, 2010/05/11 04:00

Hi thank you very much for this tutorial. It helped me a lot. once again thankyou. But my problem is am unable to move student diagrams inside classroom. could you please tell me what should i do for this.

Jean-François Brazeau, 2010/07/07 21:33

Hi

Did you try to drag'n'drop the students ? It it suppose to work that way….

Regards,

JFB

Hadeer Younis, 2011/04/10 22:10

Hello,

First of all thanks loads for this tutorial!!! But I just have a small question: I want to create a new node in the diagram every time I create a shortcut. Do you have any idea how to do this??

Jean-François Brazeau, 2011/04/15 19:17

Hi, Could you precise what you mean by shortcut ? Regards, JFB

Hadeer Younis, 2011/04/15 19:24

You know when you drag and drop a node from the navigator to the diagram? It like creates a shortcut to that node. Or if you right click the diagram and select create shortcut from the context menu?

http://www.jevon.org/wiki/GMF_Drag_Drop <this shows what the shortcuts are exactly.

Jean-François Brazeau, 2011/04/19 21:05

Oh I'm sorry but I have not experimented the GMF shortcut feature… If you get a solution to your problem, please let me know, I should add a tutorial on this subject. Thank you.

Taha CHERFIA, 2011/05/08 09:52

Hey Jean, I'm interested in “Diagram initialization” well, i'm gonna show you what i did exactly :

private static Bigraphe createInitialModel() {
	Bigraphe bigraphe = BigrapheFactory.eINSTANCE.createBigraphe();
	Region reg = BigrapheFactory.eINSTANCE.createRegion();
	Noeud noeud = BigrapheFactory.eINSTANCE.createNoeud();
	noeud.setNom("N1");
	reg.setNom("Reg1");
	bigraphe.setNom("Bigraphe");
	reg.getContenirNoeud().add(noeud);
	bigraphe.getContenirRegions().add(reg);
	return bigraphe;
}

But when i run the Diagram my elements are stored in the Domain Model but they aren't shown in the diagram. any ideas?

Jean-François Brazeau, 2011/05/08 20:01

Bonjour,

Quelque chose me dit que vous parlez Français. Du bon vieux franglais dans le code, normalement je ne dois pas me tromper ! Ce que vous faites me paraît convenable. Peut-être avez-vous changé la signature de la méthode générée par GMF ? Celle-ci retournait bien initialement un 'Bigraphe' ?

Une question subsidiaire : les références permettant de naviguer de l'objet Bigraphe à l'objet Noeud en passant par l'objet Region sont elles bien de type Containment ?

JF

Taha CHERFIA, 2011/05/08 20:51

Bonjour, Merci de m'avoir repondu ^^

  • avez-vous changé la signature de la méthode générée par GMF ?
    • Oui j'ai changé la signature : @generated NOT
  • Celle-ci retournait bien initialement un 'Bigraphe' ?
    • Oui, avec la property Nom = Bigraphe
  • Une question subsidiaire : les références permettant de naviguer de l'objet Bigraphe à l'objet Noeud en passant par l'objet Region sont elles bien de type Containment ?
    • j'ai vérifié mon fichier Bigraphe.gmfmap les références sont de type : Child Reference avec la property Containment Feature = ContenirNoeud: Noeud par rapport au Node: Region

voilà une capture d'écran pour le fichier Domain Model du diagramme http://i55.tinypic.com/2qki70m.jpg

Jean-François Brazeau, 2011/05/10 19:08

Bonsoir,

Ma dernière question portait plus sur le modèle ecore que vous avez produit mais la capture d'écran fournie répond à ma question. La hiérarchie des noeuds montrent que nous avons bien des références de type containment. Dans ces cas là je ne vois pas vu de l'extérieur d'erreur dans les éléments apporté. Je repartirais de zéro à votre place pour regénérer un éditeur de diagramme GMF pour re-vérifier que vous n'avez pas fait d'erreur dans les différentes étapes.

JFB

Taha CHERFIA, 2011/05/10 20:23

Merci pour votre aide! une autre question, j'ai cette error “Top level node 'Containment Feature' must be available in the diagram 'Domain Element' or its super-class”. comment puis-je régler ce problème?

Merci d'avance.

Jean-François Brazeau, 2011/05/11 18:26

Les Top Node Reference ne peuvent être associées qu'à des éléments (features) de type containement de l'élément de base sur lequel s'appuie votre diagramme (je crois qu'il s'agit du Bigraphe dans votre cas). Les autres éléments doivent être déclarés sous forme de Child Reference ensuite.

Vous pouvez jeter un oeil à cet exemple : http://gmfsamples.tuxfamily.org/wiki/lib/exe/fetch.php?cache=&media=gmf-tuto5-gmfmap.png tiré du tutorial 5.

JFB

Taha CHERFIA, 2011/05/11 18:54

Merci Jean, mais j'ai des noeuds imbriqués es-que ça pose un problème?

voilà mon Mapping Model : http://i53.tinypic.com/oh4nxs.png

Taha CHERFIA, 2011/05/19 17:45

Bonjour Mr.Jean, merci beaucoup pour votre aide, mon problème est résolu, merci encore une fois

Taha CHERFIA, 2011/05/08 21:06

juste une petite remarque, j'utilise OSATE (Environnement de manipulation des descriptions AADL)

Jean-François Brazeau, 2011/05/10 19:09

Je ne connais pas ce produit. Est-ce une surcouche de GMF ?

Taha CHERFIA, 2011/05/10 20:16

OSATE est un environnement de manipulation des descriptions AADL qui utilise EMF pour définir “AADL Meta Model” et utilise GMF pour générer “Graphic AADL Editor”. et voilà un exemple : http://i53.tinypic.com/dx1dza.jpg

Hoang Pham, 2011/11/16 17:00

Hi,

I just want to submit a quick notice. In the Tooling definition, you wrote: “School is not checked because, later in this tutorial, we will make it automatically available when a new diagram is initiated”

But in the screenshot shown, you included School in the checkbox. Please correct it!

Thank you very much for this useful tutorial.

Jean-François Brazeau, 2011/12/06 20:40

Hi !

You are perfectly right !!!! This is corrected.

Best regards,

JFB

Lilia Milanova, 2012/07/29 00:07

Hello,

Thanks a lot for the great tutorial.

I have one question. I am creating a model with similar compartment with horizontal layout. However I want to be able to drag-n-drop a child (e.g. classroom) out of the parent compartment (e.g school) and put it somewhere else in the diagram (maybe in another compartment). Do you have any idea how can I do that?

Thanks, Lily

Abhinai, 2012/07/31 20:26

Nice tutorial!! Worth spending time. I have a question. In the above example, why can't we create ContraintToolBarLayout instead of BorderLayout while creating gmfgraph? Why do we need to modify code?

Pramod, 2012/08/29 06:11

Hi ,

Very Nice tutorial for beginner. the default.school shows as below

<?xml version=“1.0” encoding=“UTF-8”?> <jfb.examples.gmf.school:Diagram xmi:version=“2.0” xmlns:xmi=“http://www.omg.org/XMI” xmlns:jfb.examples.gmf.school=“http:///jfb/examples/gmf/school.ecore”>

<school name="Sample">
  <classrooms name="Class Room">
    <students name="Student1" friends="//@school/@classrooms.1/@students.0"/>
  </classrooms>
  <classrooms name="Classroom 2">
    <students name="Student2"/>
  </classrooms>
</school>

</jfb.examples.gmf.school:Diagram>

If I dont want root tag i.e is <jfb.examples.gmf.school:Diagram >. what changes should I do so that my default.school looks as follows:

<school name=“Sample”>

  <classrooms name="Class Room">
    <students name="Student1" friends="//@school/@classrooms.1/@students.0"/>
  </classrooms>
  <classrooms name="Classroom 2">
    <students name="Student2"/>
  </classrooms>
</school>

Regards, Pramod

Jérome Renard, 2014/03/31 20:26

Bonjour,

J'ai vu que vous parliez français, donc je vais poser ma question en français.

Est-ce que c'est possible de faire la même chose sans pour autant avoir un noeud “Root” dans le modèle ecore (ici “Diagram”), parce que ça embrouille le fichier XML en sortie.

Bien à vous.

JR

Roman, 2014/12/16 17:00

I tried to do all steps described in this tutorial on Eclipse Luna 4.4.1. I got many errors in the generated School.diagramm

1)Many exceptions were in the dialog, which was open during generation, all of them like Exception (Boolean expected (was: org.eclipse.ocl.ecore.internal.OCLStandardLibraryImpl$1)!:in CodeStyle, line 18) while generating code Boolean expected (was: org.eclipse.ocl.ecore.internal.OCLStandardLibraryImpl$1)!:in CodeStyle, line 18

2)Generated plugin was without manifest file and also without dependencies. I manually added dependencies

3) The last type of problems were because not all code was generated, some classes referenced to another which wasn't generated at all: jfb.examples.gmf.school.model.diagram.edit.policies.ClassroomClassroomStudentsCompartmentCanonicalEditPolicy; jfb.examples.gmf.school.model.diagram.part.SchoolVisualIDRegistry; jfb.examples.gmf.school.model.diagram.providers.SchoolElementTypes; jfb.examples.gmf.school.model.diagram.edit.policies.ClassroomItemSemanticEditPolicy; jfb.examples.gmf.school.model.diagram.part.SchoolVisualIDRegistry;

and so on.

I tried to do other GMF tutorials and result was the same. Could be possible that GMF doesn't work with eclipse luna?

 
gmf_tutorial7.txt · Last modified: 2011/08/08 20:07 by jfbraz
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki