Project: org.openscada.orilla
/*
 * This file is part of the OpenSCADA project 
 * Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com) 
 * 
 * OpenSCADA is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU Lesser General Public License version 3 
 * only, as published by the Free Software Foundation. 
 * 
 * OpenSCADA is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU Lesser General Public License version 3 for more details 
 * (a copy is included in the LICENSE file that accompanied this code). 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * version 3 along with OpenSCADA. If not, see 
 * <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License. 
 */
 
package org.openscada.ae.ui.views.dialog; 
 
import java.util.ArrayList; 
import java.util.List; 
 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.custom.CTabFolder; 
import org.eclipse.swt.custom.CTabItem; 
import org.eclipse.swt.custom.ScrolledComposite; 
import org.eclipse.swt.events.DisposeEvent; 
import org.eclipse.swt.events.DisposeListener; 
import org.eclipse.swt.events.KeyAdapter; 
import org.eclipse.swt.events.KeyEvent; 
import org.eclipse.swt.events.SelectionAdapter; 
import org.eclipse.swt.events.SelectionEvent; 
import org.eclipse.swt.graphics.Point; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.layout.RowData; 
import org.eclipse.swt.layout.RowLayout; 
import org.eclipse.swt.widgets.Button; 
import org.eclipse.swt.widgets.Combo; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.swt.widgets.Label; 
import org.eclipse.swt.widgets.Listener; 
import org.eclipse.swt.widgets.Text; 
import org.openscada.ae.Event; 
import org.openscada.ae.Event.Fields; 
import org.openscada.ae.ui.views.Messages; 
import org.openscada.utils.filter.Assertion; 
import org.openscada.utils.filter.Filter; 
import org.openscada.utils.filter.FilterAssertion; 
import org.openscada.utils.filter.FilterExpression; 
import org.openscada.utils.filter.Operator; 
 
public class FilterAdvancedComposite extends Composite 
    private final List<OrCondition> orConditions = new ArrayList<OrCondition> (); 
 
    private final CTabFolder tabFolder; 
 
    private final Button addOrConditionButton; 
 
    private enum Type 
    { 
        Text, 
        Number, 
        DateTime 
    } 
 
    /**
     * @author jrose 
     * 
     */
 
    private static class AddAssertionComposite extends Composite 
    { 
        // fields 
        private final OrCondition orCondition; 
 
        // widgets 
        private final Combo attributeCombo; 
 
        public AddAssertionComposite ( final OrCondition orCondition, final Composite parent ) 
        { 
            // fields 
            super ( parent, SWT.NONE ); 
            this.orCondition = orCondition; 
 
            // widgets 
            this.attributeCombo = createAttributeCombo (); 
            createTypeCombo (); 
            createAddButton (); 
 
            // layout 
            final RowLayout layout = new RowLayout (); 
            this.setLayout ( layout ); 
        } 
 
        private Combo createAttributeCombo () 
        { 
            final Combo c = new Combo ( this, SWT.NONE ); 
            c.add ( "sourceTimestamp" ); //$NON-NLS-1$ 
            c.add ( "entryTimestamp" ); //$NON-NLS-1$ 
            for ( final Event.Fields field : Event.Fields.values () ) 
            { 
                c.add ( field.getName () ); 
            } 
            c.add ( Messages.custom_field ); 
            c.select ( 0 ); 
            return c; 
        } 
 
        private Combo createTypeCombo () 
        { 
            final Combo c = new Combo ( this, SWT.NONE ); 
            for ( final Type type : Type.values () ) 
            { 
                c.add ( type.name () ); 
            } 
            c.select ( 0 ); 
            return c; 
        } 
 
        private Button createAddButton () 
        { 
            final Button b = new Button ( this, SWT.PUSH ); 
            b.setText ( Messages.add_assertion ); 
            b.addSelectionListener ( new SelectionAdapter () { 
                @Override 
                public void widgetSelected ( final SelectionEvent e ) 
                { 
                    AddAssertionComposite.this.orCondition.addAssertion (); 
                } 
            } ); 
            return b; 
        } 
    } 
 
    /**
     *  
     * @author jrose 
     */
 
    private static class AssertionComposite extends Composite 
    { 
        // fields 
        private final OrCondition orCondition; 
 
        // widgets 
        private final Button notCheck; 
 
        private final Text attributeText; 
 
        private final Text valueText; 
 
        private final Combo assertionCombo; 
 
        public AssertionComposite ( final OrCondition orCondition, final Composite parent, final String attribute, final Type type ) 
        { 
            // final fields 
            super ( parent, SWT.NONE ); 
            this.orCondition = orCondition; 
 
            // widgets 
            this.notCheck = createNotCheck (); 
            this.attributeText = createAttributeText ( attribute ); 
            createFieldTypeLabel ( type ); 
            this.assertionCombo = createAssertionCombo (); 
            this.valueText = createValueText (); 
            createRemoveButton (); 
 
            // layout 
            final RowLayout layout = new RowLayout (); 
            layout.center = true
            this.setLayout ( layout ); 
 
            parent.notifyListeners ( SWT.Resize, new org.eclipse.swt.widgets.Event () ); 
        } 
 
        private Button createNotCheck () 
        { 
            final Button b = new Button ( this, SWT.CHECK ); 
            b.setText ( Messages.not ); 
            b.addSelectionListener ( new SelectionAdapter () { 
                @Override 
                public void widgetSelected ( final SelectionEvent e ) 
                { 
                    AssertionComposite.this.orCondition.updateFilter (); 
                } 
            } ); 
            return b; 
        } 
 
        private Text createAttributeText ( final String attribute ) 
        { 
            final Text t = new Text ( this, SWT.BORDER ); 
            final Fields field = Fields.byField ( attribute ); 
            if ( field == null ) 
            { 
                t.setEditable ( true ); 
                t.setMessage ( Messages.custom_field ); 
            } 
            else 
            { 
                t.setEditable ( false ); 
                t.setText ( field.getName () ); 
            } 
            t.addKeyListener ( new KeyAdapter () { 
                @Override 
                public void keyReleased ( final KeyEvent e ) 
                { 
                    AssertionComposite.this.orCondition.updateFilter (); 
                }; 
            } ); 
            final RowData rowData = new RowData (); 
            rowData.width = 132
            t.setLayoutData ( rowData ); 
            return t; 
        } 
 
        private Label createFieldTypeLabel ( final Type type ) 
        { 
            final Label l = new Label ( this, SWT.NONE ); 
            l.setText ( type.name () ); 
            return l; 
        } 
 
        private Combo createAssertionCombo () 
        { 
            final Combo c = new Combo ( this, SWT.NONE ); 
            for ( final Assertion assertion : Assertion.values () ) 
            { 
                c.add ( assertion.toString () ); 
            } 
            c.select ( 0 ); 
            c.addSelectionListener ( new SelectionAdapter () { 
                @Override 
                public void widgetSelected ( final SelectionEvent e ) 
                { 
                    AssertionComposite.this.orCondition.updateFilter (); 
                } 
            } ); 
            final RowData rowData = new RowData (); 
            rowData.width = 75
            c.setLayoutData ( rowData ); 
            return c; 
        } 
 
        private Text createValueText () 
        { 
            final Text t = new Text ( this, SWT.BORDER ); 
            t.setMessage ( Messages.argument ); 
            t.addKeyListener ( new KeyAdapter () { 
                @Override 
                public void keyReleased ( final KeyEvent e ) 
                { 
                    AssertionComposite.this.orCondition.updateFilter (); 
                } 
            } ); 
            final RowData rowData = new RowData (); 
            rowData.width = 132
            t.setLayoutData ( rowData ); 
            return t; 
        } 
 
        private Button createRemoveButton () 
        { 
            final Button b = new Button ( this, SWT.PUSH ); 
            b.setText ( Messages.remove ); 
            b.addSelectionListener ( new SelectionAdapter () { 
                @Override 
                public void widgetSelected ( final SelectionEvent e ) 
                { 
                    AssertionComposite.this.orCondition.removeAssertion ( AssertionComposite.this ); 
                } 
            } ); 
            return b; 
        } 
 
        public Filter getExpression () 
        { 
            final String attr = this.attributeText.getText (); 
            final String ass = this.assertionCombo.getText (); 
            final String val = this.valueText.getText (); 
            final FilterAssertion assertion = new FilterAssertion ( attr, Assertion.fromString ( ass ), val ); 
            if ( val.contains ( "*" ) ) //$NON-NLS-1$ 
            { 
                assertion.setAssertion ( Assertion.SUBSTRING ); 
                assertion.setValue ( val.split ( "\\*" ) ); //$NON-NLS-1$ 
            } 
            if ( this.notCheck.getSelection () ) 
            { 
                return FilterExpression.negate ( assertion ); 
            } 
            return assertion; 
        } 
    } 
 
    /**
     * @author jrose 
     * 
     */
 
    private static class OrCondition 
    { 
        private final FilterAdvancedComposite filterAdvancedComposite; 
 
        private final CTabItem tabItem; 
 
        private final Composite tabContent; 
 
        private final List<AssertionComposite> assertionComposites = new ArrayList<AssertionComposite> (); 
 
        private final AddAssertionComposite addAssertionComposite; 
 
        private final ScrolledComposite assertionScrolledComposite; 
 
        private final Composite assertionComposite; 
 
        public OrCondition ( final FilterAdvancedComposite filterAdvancedComposite, final CTabFolder tabFolder ) 
        { 
            // fields 
            this.filterAdvancedComposite = filterAdvancedComposite; 
            this.tabItem = new CTabItem ( tabFolder, SWT.NULL ); 
            this.tabItem.setText ( Messages.a_condition ); 
            this.tabContent = new Composite ( tabFolder, SWT.NONE ); 
            this.tabItem.setControl ( this.tabContent ); 
 
            // widgets 
            this.addAssertionComposite = new AddAssertionComposite ( thisthis.tabContent ); 
            this.assertionScrolledComposite = new ScrolledComposite ( this.tabContent, SWT.V_SCROLL | SWT.NONE ); 
            this.assertionComposite = new Composite ( this.assertionScrolledComposite, SWT.NONE ); 
            this.assertionScrolledComposite.setContent ( this.assertionComposite ); 
 
            // layout 
            final GridLayout layout = new GridLayout (); 
            layout.marginLeft = 6
            layout.marginRight = 6
            layout.marginTop = 6
            layout.marginBottom = 6
            layout.verticalSpacing = 12
            this.tabContent.setLayout ( layout ); 
 
            final GridData addAssertionCompositeLayoutData = new GridData (); 
            addAssertionCompositeLayoutData.grabExcessHorizontalSpace = true
            addAssertionCompositeLayoutData.horizontalAlignment = GridData.FILL; 
            this.addAssertionComposite.setLayoutData ( addAssertionCompositeLayoutData ); 
 
            final GridData assertionCompositeLayoutData = new GridData (); 
            assertionCompositeLayoutData.grabExcessHorizontalSpace = true
            assertionCompositeLayoutData.horizontalAlignment = GridData.FILL; 
            assertionCompositeLayoutData.grabExcessVerticalSpace = true
            assertionCompositeLayoutData.verticalAlignment = GridData.FILL; 
            this.assertionScrolledComposite.setLayoutData ( assertionCompositeLayoutData ); 
            this.assertionScrolledComposite.setExpandHorizontal ( true ); 
 
            final RowLayout innerlayout = new RowLayout ( SWT.VERTICAL ); 
            innerlayout.wrap = false
            this.assertionComposite.setLayout ( innerlayout ); 
            this.assertionComposite.addListener ( SWT.Resize, new Listener () { 
                public void handleEvent ( final org.eclipse.swt.widgets.Event event ) 
                { 
                    final Point s = OrCondition.this.assertionComposite.computeSize ( SWT.DEFAULT, SWT.DEFAULT ); 
                    OrCondition.this.assertionComposite.setSize ( s.x, s.y ); 
                    refreshGUI (); 
                } 
            } ); 
        } 
 
        private void refreshGUI () 
        { 
            this.filterAdvancedComposite.refreshGUI (); 
        } 
 
        public void addAssertion () 
        { 
            this.assertionComposites.add ( new AssertionComposite ( thisthis.assertionComposite, this.addAssertionComposite.attributeCombo.getText (), Type.Text ) ); 
            refreshGUI (); 
            updateFilter (); 
        } 
 
        public void removeAssertion ( final AssertionComposite assertion ) 
        { 
            this.assertionComposites.remove ( assertion ); 
            assertion.dispose (); 
            refreshGUI (); 
            if ( this.assertionComposites.size () == 0 ) 
            { 
                this.tabItem.setText ( Messages.a_condition ); 
            } 
        } 
 
        public FilterExpression getExpression () 
        { 
            final FilterExpression expression = new FilterExpression (); 
            expression.setOperator ( Operator.AND ); 
            for ( final AssertionComposite assertionComposite : this.assertionComposites ) 
            { 
                expression.getFilterSet ().add ( assertionComposite.getExpression () ); 
            } 
            return expression; 
        } 
 
        private void updateFilter () 
        { 
            this.tabItem.setText ( getExpression ().toString ().replace ( "&""&&" ) ); //$NON-NLS-1$ //$NON-NLS-2$ 
        } 
    } 
 
    public FilterAdvancedComposite ( final FilterChangedListener filterChangedListener, final Composite parent, final int style ) 
    { 
        // fields 
        super ( parent, style ); 
 
        // widgets 
        this.tabFolder = new CTabFolder ( this, SWT.TOP | SWT.BORDER | SWT.CLOSE ); 
        this.addOrConditionButton = creteAddOrConditionButton (); 
        addOrCondition (); 
 
        // layout 
        final GridLayout layout = new GridLayout ( 1true ); 
        layout.marginLeft = 6
        layout.marginRight = 6
        layout.marginTop = 6
        layout.marginBottom = 6
        layout.verticalSpacing = 12
        this.setLayout ( layout ); 
 
        final GridData tabFolderLayoutData = new GridData (); 
        tabFolderLayoutData.horizontalAlignment = GridData.FILL; 
        tabFolderLayoutData.grabExcessHorizontalSpace = true
        tabFolderLayoutData.verticalAlignment = GridData.FILL; 
        tabFolderLayoutData.grabExcessVerticalSpace = true
        this.tabFolder.setLayoutData ( tabFolderLayoutData ); 
        this.tabFolder.setBackgroundMode ( SWT.INHERIT_FORCE ); 
 
        final GridData addOrConditionButtonLayoutdata = new GridData (); 
        addOrConditionButtonLayoutdata.horizontalAlignment = GridData.END; 
        this.addOrConditionButton.setLayoutData ( addOrConditionButtonLayoutdata ); 
    } 
 
    private Button creteAddOrConditionButton () 
    { 
        final Button b = new Button ( this, SWT.PUSH ); 
        b.setText ( Messages.add_or_condition ); 
        b.addSelectionListener ( new SelectionAdapter () { 
            @Override 
            public void widgetSelected ( final SelectionEvent e ) 
            { 
                addOrCondition (); 
            } 
        } ); 
        b.addDisposeListener ( new DisposeListener () { 
            public void widgetDisposed ( final DisposeEvent e ) 
            { 
                final int i = FilterAdvancedComposite.this.tabFolder.getSelectionIndex (); 
                FilterAdvancedComposite.this.orConditions.remove ( i ); 
            } 
        } ); 
        return b; 
    } 
 
    private void addOrCondition () 
    { 
        this.orConditions.add ( new OrCondition ( thisthis.tabFolder ) ); 
        this.tabFolder.setSelection ( this.tabFolder.getItemCount () - 1 ); 
        refreshGUI (); 
    } 
 
    private void refreshGUI () 
    { 
        this.layout ( truetrue ); 
    } 
}