Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Custom CSS parsing
Custom CSS parsing [message #1709605] Tue, 29 September 2015 13:56 Go to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2902
Registered: July 2012
Senior Member
Hi,

I'm trying to implement CSS styling for NatTable. The styling in NatTable is already decoupled, so in theory a CSS only needs to be parsed and translated to NatTable styling.

Unfortunately the Eclipse CSSEngine is working differently than I suspected. It seems to only parse the style rule that applies to a widget terms of class and/or id.

What I need is that all style rules are parsed and applied for a class. In NatTable we support contextual styling via cell labels. Since we don't have real child objects within a NatTable (according to the Widget hierarchy supposed by the CSSEngine implementation) I don't see how to achieve CSS styling based on labels.

I was playing around with several ways. First I tried to use additional IDs. But they are not transported to applyCSSProperty() in a handler, nor do they lead to applying the style in any way since it doesn't match the CSS rule. Thinking more about that, that approach doesn't even fit the CSS concepts.

So the next id was to have some sort of virtual children. Like specifying something like this

NatTable > COLUMN_HEADER {
	cell-background-color: blue;
}


Where COLUMN_HEADER could be treated as child. But again I don't get the information about the child, nor does the selector ever match.

I also have an issue creating the adapter and specifying pseudo instances. I thought to use pseudo instances for the DisplayModes. For example the following style rule would apply the cell background for selected cells

NatTable :select {
	cell-background-color: green;
}


And I configured the pseudo instances in the adapter this way

public NatTableElementAdapter(NatTable natTable, CSSEngine engine) {
        super(natTable, engine);

        addStaticPseudoInstance("normal");
        addStaticPseudoInstance("select");
        addStaticPseudoInstance("edit");
        addStaticPseudoInstance("hover");
        addStaticPseudoInstance("select-hover");
}


Strangely this only works if I implement getParentNode() like this

    @Override
    public Node getParentNode() {
        return this;
    }


If I return null or the Control parent like in ControlElement, the pseudo instances doesn't work for me.


At some point I was thinking about dynamic style properties. So users could for example prefix a style property with the label and we achieve the conditional styling this way. Not very elegant when thinking about CSS, but a way. But it also seems that dynamic properties doesn't work because properties need to be defined in the extension point.

I am digging through the code since a few days, but I don't find any solution. It seems I can't influence the parsing nor can I change the CSSEngine implementation.

Does anybody have an idea on this, or am I really lost in creating a NatTable own way of parsing and applying CSS styles because the E4 CSSEngine doesn't support the NatTable structure?

Any help appreciated!

Greez,
Dirk
Re: Custom CSS parsing [message #1709643 is a reply to message #1709605] Tue, 29 September 2015 21:24 Go to previous messageGo to next message
Eclipse UserFriend
You haven't provided enough information for me to figure out what you're doing or doing wrong. So let me explain how the CSS engine works... I think that might explain some of the issues you're hitting.

The CSS engine works against a tree-based model called the DOM. Each node in the tree is also called an element and an adapter, which can be confusing. The DOM is created from some other model; in the SWT CSS Engine, the DOM is build from a widget tree, where each DOM element corresponds to a widget, created using an element provider. The DOM elements provide a name (getLocalName()) and namespace (getNamespaceURI()), and a set of attributes. The SWT DOM elements use the SWT widget class name. In CSS the identifier and class have well known names ('id' and 'class').

The CSS is parsed and turned into a set of rules. Each rule has a selector and a set of properties. The selector is a predicate that decides whether it matches a DOM element or not.

The CSS engine itself walks the DOM from some provided root node and checks if it has rules that apply. For each element walks, it checks all rules by checking the element against that rule's selector. For each match, it then applies the rule's properties to the DOM element. The actual property handlers are looked up both by element type (called the 'adapter') and property name.

You can add dynamically expose pseudo instances -- basically you implement isPseudoInstanceOf() and, when that condition changes, trigger the engine to re-evaluate the DOM from that widget's corresponding element. See ControlElement and its focusListener. (We disable the dynamic pseudo instances support as the implemented approach doesn't scale to large widget trees.) Static pseudo instances are always applicable (e.g., derived from SWT style bits set in the constructor -- like read-only).

You would normally create a NatTableElement to represent your NatTable instance. There is no requirement that a DOM element actually map to something concrete (e.g., a widget or a class instance): your NatTableElement could expose a virtual element to correspond to internal properties (e.g., a NatTableColumnElement). If your columns have an id, your elements could expose that as their CSS id. Your property handlers can work with the element You could also expose fixed properties of your column as CSS classes or attributes.

The engine doesn't provide details on the selector used to match the elements, but rather identifies elements that match a selector. This means the handlers can't introspect on the selector to be clever. For example, it might be nice to have a 'background' handler be able to interpret something like:

NatTable Row:odd { background: blue; }

to mean that odd rows should have a blue background. A naive approach, which is implemented but not actually hooked up for TableElement / TableItemElement, would have the NatTable expose each row as an element and have a pseudo-instance for 'odd' and 'even'. But that means a table of 100,000 rows would need to expose 100,000 row objects. Ugh.

An alternative approach is to have NatTableElement expose two virtual 'Row' elements for static pseudo instances 'odd' and 'even'. Then the background handler could check the provided element for whether it has 'odd' or 'even' and apply the changes to the NatTable.

To address two points in your message:

Quote:

Where COLUMN_HEADER could be treated as child. But again I don't get the information about the child, nor does the selector ever match.


The selector matches against the COLUMN_HEADER element and, if matched, then your handler receives the COLUMN_HEADER element. You can put a breakpoint in AbstractCSSEngine#matches() to see how/why your element isn't being matched.

(Your NatTable ElementAdapter is returning an element for the COLUMN_HEADER in getChildren() right?)

Quote:

NatTable :select {


Realize that selector is a compound selector that matches an element with :select with an ancestor named NatTable. The space is significant.

Brian.
Re: Custom CSS parsing [message #1709663 is a reply to message #1709643] Wed, 30 September 2015 07:40 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2902
Registered: July 2012
Senior Member
Hi Brian,

thanks a lot for the detailed explanation. I know the DOM, but it never hurts to get it explained in another context again. Smile

Your explanations helped in getting further with my investigations.

First, the space used with my pseudo selector. Removing the space now leads to correct parsing of the pseudo. Thanks, I always forget about the correct selector definition.
Second, the virtual children approach. You are right, there is no COLUMN_HEADER child returned. The child implementation in the adapters look strange (getChildren() returns the adapter itself but the inspection of the children happens using different methods that operate on a child collection?), but I will try to find a way for this. Maybe via wrapper or a proxy. Need to think about this.

Regarding your row approach idea, that doesn't fit the NatTable architecture (for sake when thinking about huge amount of rows Wink ). The idea is to have a virtual child for every label, that wraps or proxies the NatTable, so I am able to transport the label for NatTable style registration.

Thanks again, I think that points into the right direction for using the Eclipse 4 CSS engine.

I keep you informed about my results.

Greez,
Dirk
Re: Custom CSS parsing [message #1709885 is a reply to message #1709663] Thu, 01 October 2015 17:34 Go to previous messageGo to next message
Eclipse UserFriend
Dirk Fauth wrote on Wed, 30 September 2015 03:40

Second, the virtual children approach. You are right, there is no COLUMN_HEADER child returned. The child implementation in the adapters look strange (getChildren() returns the adapter itself but the inspection of the children happens using different methods that operate on a child collection?), but I will try to find a way for this. Maybe via wrapper or a proxy. Need to think about this.


Yeah, the self-implementing NodeList decision is weird. I'm not sure why it was done, as #getChildNodes() can return null to indicate no children.

You don't *have* to extend WidgetElement.

Quote:

Regarding your row approach idea, that doesn't fit the NatTable architecture (for sake when thinking about huge amount of rows Wink ). The idea is to have a virtual child for every label, that wraps or proxies the NatTable, so I am able to transport the label for NatTable style registration.


That's actually the approach I suggested Smile

Good luck!

Brian.
Re: Custom CSS parsing [message #1710082 is a reply to message #1709885] Sat, 03 October 2015 23:31 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2902
Registered: July 2012
Senior Member
After struggling a while with the implementations I finally got the virtual children work with the e4 CSS engine. My brain still hurts, but it works. Smile

But there is one thing that still doesn't work. And that is the initial application of children styles. The internally registered CSSSWTApplyStylesListener is not applying the styles for the children. So the virtual children styles get only applied after I click into the NatTable.

Is there an elegant way to apply the children styles on skinning too? I haven't found anything in the code and I personally don't understand why the children are not processed on skinning. Maybe a performance reason?

Nevertheless, is the only way to solve this to add an additional listener that performs children styling too? I don't want to create a new PartRenderingEngine just because of that little parameter.
Re: Custom CSS parsing [message #1710121 is a reply to message #1710082] Sun, 04 October 2015 17:18 Go to previous message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2902
Registered: July 2012
Senior Member
I now realized that I have another issue regarding the selectors. The combination of pseudo and child doesn't work.

The idea is to configure a style e.g. for pseudo selection and child selectionAnchor. From my understanding this should work:

NatTable:select > .selectionAnchor {
	cell-background-color: red;
}


But I can't get this to work. On debugging I realized that the selector does never match because of CSSChildSelectorImpl#match()

    @Override
	public boolean match(Element e, String pseudoE) {
        Node n = e.getParentNode();
        if (n != null && n.getNodeType() == Node.ELEMENT_NODE) {
            return ((ExtendedSelector)getAncestorSelector()).match((Element)n,
                                                                   null) &&
                   ((ExtendedSelector)getSimpleSelector()).match(e, pseudoE);
        }
        return false;
    }


The ancestor selector is always tested with pseudo == null. The ancestor in that case is CSSPseudoClassConditionImpl, which returns false because the pseudo parameter is null on checking the pseudo 'select'.

Then I tried this:

NatTable > .selectionAnchor:select {
	cell-background-color: red;
}


But in that case I have an issue in AbstractCSSEngine#applyConditionalPseudoStyle(), because the resulting style rule (yes, with the above selector the style is parsed correctly) is not applied. This is because the returned CSSChildSelectorImpl is not a ConditionalSelector.


Either my idea on this or my selector usage is wrong. In that case, could you please correct me and tell me how it should look like?

Otherwise there is a bug in CSSChildSelectorImpl and the ancestor test shouldn't be performed with pseudo == null or the usage of AbstractCSSEngine#applyConditionalPseudoStyle() is not correct.

Any insights, ideas and help appreciated. If it is a bug, I'm happy to contribute the appropriate fix.

Greez,
Dirk

[Updated on: Sun, 04 October 2015 18:28]

Report message to a moderator

Previous Topic:Compatibility Layer restore detached Folder?
Next Topic:Set the input on a part at runtime
Goto Forum:
  


Current Time: Tue Apr 23 16:17:58 GMT 2024

Powered by FUDForum. Page generated in 0.03311 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top