[Title] common-eplugin: added DynamicDialog using UserField model for Prompter
authorJihoon Song <jihoon80.song@samsung.com>
Wed, 14 Nov 2012 07:24:34 +0000 (16:24 +0900)
committerJihoon Song <jihoon80.song@samsung.com>
Wed, 14 Nov 2012 07:33:54 +0000 (16:33 +0900)
[Desc.]
[Issue]

Change-Id: I208f75e23c055001693919209c65089009f9d33b

org.tizen.common/META-INF/MANIFEST.MF
org.tizen.common/src/org/tizen/common/ui/dialog/DynamicDialog.java [new file with mode: 0644]

index 9378167..a27ca2e 100755 (executable)
@@ -8,7 +8,8 @@ Require-Bundle: org.eclipse.ui,
  org.eclipse.core.runtime,
  org.eclipse.ui.ide,
  org.eclipse.core.resources,
- org.eclipse.core.filesystem
+ org.eclipse.core.filesystem,
+ org.junit4;bundle-version="4.8.1";resolution:=optional
 Export-Package: 
  freemarker.cache,
  freemarker.core,
diff --git a/org.tizen.common/src/org/tizen/common/ui/dialog/DynamicDialog.java b/org.tizen.common/src/org/tizen/common/ui/dialog/DynamicDialog.java
new file mode 100644 (file)
index 0000000..97474b2
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * Jihoon Song <jihoon80.song@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.ui.dialog;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+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.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.tizen.common.core.command.InputValidator;
+import org.tizen.common.core.command.PrompterConstants;
+import org.tizen.common.core.command.UserField;
+import org.tizen.common.util.Assert;
+import org.tizen.common.util.CollectionUtil;
+import org.tizen.common.util.SWTUtil;
+
+
+/**
+ * Dialog for creating control dynamically using UserField models.
+ * Types of "String, char[], boolean" are currently supported.
+ * 
+ * @author JIhoon Song {@literal<jihoon80.song@samsung.com>}
+ */
+public class DynamicDialog extends Dialog {
+
+    protected final Logger logger = LoggerFactory.getLogger( getClass() );
+    
+    protected String title = "Dynamic Dialog"; // default. If you want to change, use setter.
+    protected int width = 500; // default. This is fixed currently. 
+    
+    // inputted fields
+    protected Collection<UserField> fields;
+    
+    // ID based controls for searching
+    protected Map<String, Control> controlMap = new HashMap<String, Control>();
+    
+    
+    /////////////////////////////////////////////////////////////////
+    // Constructor
+    
+    /**
+     * Default constructor for dynamic generation
+     * @param parent parent shell
+     * @param userFields {@link UserField}
+     */
+    public DynamicDialog(Shell parent, Collection<UserField> fields) {
+        super( parent );
+        Assert.notNull( fields );
+        
+        this.fields = fields;
+    }
+    
+    public DynamicDialog(IShellProvider parentShell, Collection<UserField> fields) {
+        super( parentShell );
+        Assert.notNull( fields );
+        
+        this.fields = fields;
+    }
+    
+    /**
+     * Constructor for dynamic generation using current active shell
+     * @param userFields {@link UserField}
+     */
+    public DynamicDialog(Collection<UserField> fields) {
+        this( SWTUtil.getActiveShell(), fields );
+    }
+    
+    
+    /////////////////////////////////////////////////////////////////
+    // Dialog logic
+    
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    @Override
+    protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        
+        newShell.setText( getTitle() );
+    }
+
+    @Override
+    protected Point getInitialSize() {
+        Point initialSize = super.getInitialSize();
+        
+        initialSize.x = this.width;
+        
+        return initialSize;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.jface.dialogs.Dialog#createContents(org.eclipse.swt.widgets.Composite)
+     */
+    @Override
+    protected Control createContents(Composite parent) {
+        // create super dialog control
+        Composite superContents = (Composite) super.createContents( parent );
+        
+        Control dialogArea = this.getDialogArea();
+        boolean firstControl = true;
+        for ( UserField field : this.fields ) {
+            // create dynamic dialog control
+            Control control = createDynamicControl( (Composite) dialogArea, field );
+            
+            // set focus to first control
+            if ( firstControl && control != null ) {
+                firstControl = false;
+                control.setFocus();
+                if ( control instanceof Text ) {
+                    ((Text) control).selectAll();
+                }
+            }
+            
+            // initialize child's status
+            if ( control instanceof Button ) {
+                enableChildControls( field.getId(), getBoolean( field.getValue() ) );
+            }
+        }
+        
+        return superContents;
+    }
+    
+    /**
+     * Dynamically create control with field information
+     * @param parent control
+     * @return created control
+     */
+    protected Control createDynamicControl(Composite parent, final UserField field) {
+        Control control = null;
+        
+        // filtering unsupported field
+        if ( !isSupportField( field ) ) {
+            return null;
+        }
+        
+        // create control
+        Class<?> type = field.getType();
+        if ( String.class.equals( type ) ) {
+            control = createStringTypeControl( parent, field );
+        } else if ( char[].class.equals( type ) || Character[].class.equals( type ) ) {
+            control = createCharacterTypeControl( parent, field );
+        } else if ( boolean.class.equals( type ) || Boolean.class.equals( type ) ) {
+            control = createBooleanTypeControl( parent, field );
+        } else {
+            throw new IllegalArgumentException( "Unsupported user field type." );
+        }
+        
+        // create child controls
+        Collection<UserField> children = field.getChildren();
+        if ( children != null ) {
+            Composite composite = createComposite( parent, new GridLayout(), new GridData( GridData.FILL_BOTH ) );
+            
+            for ( UserField childField : children ) {
+                createDynamicControl( composite, childField );
+            }
+        }
+        
+        // return created control
+        return control;
+    }
+    
+    /**
+     * If support list is nothing or the "eclipse" exist, allow control creation.
+     * @param field {@link UserField} with support list
+     * @return If can support, return true. otherwise, return false
+     */
+    protected boolean isSupportField(final UserField field) {
+        Collection<Object> supports = field.getSupports();
+        if ( null != supports && !supports.contains( PrompterConstants.SUPPORT_IDE ) ) {
+            logger.warn( "{} is not supported in {}", field, this );
+            return false;
+        }
+        
+        return true;
+    }
+    
+    
+    /////////////////////////////////////////////////////////////////
+    // style getter
+    
+    /**
+     * If you want, override this.
+     * @return Composite's default style
+     */
+    public int getCompositeStyle() {
+        return SWT.NONE;
+    }
+    
+    /**
+     * If you want, override this.
+     * @return Text's default style
+     */
+    public int getTextStyle() {
+        return SWT.SINGLE;
+    }
+    
+    
+    /**
+     * If you want, override this.
+     * @return Text's default style for password
+     */
+    public int getPasswordTextStyle() {
+        return getTextStyle() | SWT.PASSWORD;
+    }
+    
+    
+    /**
+     * If you want, override this.
+     * @return Label's default style
+     */
+    public int getLabelStyle() {
+        return SWT.WRAP;
+    }
+    
+    
+    /**
+     * If you want, override this.
+     * @return Button's default style for Check
+     */
+    public int getCheckButtonStyle() {
+        return SWT.CHECK | SWT.CENTER;
+    }
+    
+    
+    /////////////////////////////////////////////////////////////////
+    // create controls for type
+    
+    protected Text createStringTypeControl(Composite parent, final UserField field) {
+        Composite composite = createComposite( parent, new GridLayout( 2, false ), new GridData( GridData.FILL_BOTH ) );
+        
+        createLabel( composite, new GridData( GridData.HORIZONTAL_ALIGN_END ), field.getMessage(), field.canModify() );
+        Text text = createText( composite, new GridData( GridData.FILL_BOTH ), field.getValue(), field.canModify(), field.getValidator() );
+        text.addModifyListener( new ModifyListener() {
+            @Override
+            public void modifyText(ModifyEvent e) {
+                Text modifiedText = ((Text) e.widget);
+                field.setValue( modifiedText.getText() ); // synchronize model
+            }
+        } );
+        
+        this.controlMap.put( field.getId(), text );
+        
+        return text;
+    }
+    
+    protected Text createCharacterTypeControl(Composite parent, final UserField field) {
+        Composite composite = createComposite( parent, new GridLayout( 2, false ), new GridData( GridData.FILL_BOTH ) );
+        
+        createLabel( composite, new GridData( GridData.HORIZONTAL_ALIGN_END ), field.getMessage(), field.canModify() );
+        Text text = createPasswordText( composite, new GridData( GridData.FILL_BOTH ), field.getValue(), field.canModify(), field.getValidator() );
+        text.addModifyListener( new ModifyListener() {
+            @Override
+            public void modifyText(ModifyEvent e) {
+                Text modifiedText = ((Text) e.widget);
+                field.setValue( modifiedText.getText().toCharArray() ); // synchronize model
+            }
+        } );
+        
+        this.controlMap.put( field.getId(), text );
+        
+        return text;
+    }
+    
+    protected Button createBooleanTypeControl(Composite parent, final UserField field) {
+        Button button = createCheckButton( parent, new GridData( GridData.CENTER ), field.getId(), field.getMessage(), field.getValue(), field.canModify() );
+        button.addSelectionListener( new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Button modifiedButton = ((Button) e.widget);
+                field.setValue( modifiedButton.getSelection() ); // synchronize model
+            }
+        } );
+        
+        this.controlMap.put( field.getId(), button );
+        
+        return button;
+    }
+    
+    
+    /////////////////////////////////////////////////////////////////
+    // control creation utility
+    
+    private Composite createComposite(Composite parent, Layout layout, Object layoutData) {
+        Composite composite = new Composite( parent, getCompositeStyle() ) {
+            @Override
+            public void setEnabled(boolean enabled) {
+                super.setEnabled(enabled);
+                
+                for ( Control children : getChildren() ) {
+                    if ( controlMap.containsValue( children ) ) {
+                        String controlId = getKeyByValue( controlMap, children );
+                        UserField userField = getModel( fields, controlId );
+                        
+                        if ( !userField.canModify() ) {
+                            continue;
+                        }
+                    }
+                    children.setEnabled( enabled );
+                }
+            }
+        };
+        composite.setLayout( layout );
+        composite.setLayoutData( layoutData );
+        
+        return composite;
+    }
+    
+    private Label createLabel(Composite parent, Object layoutData, String msg, boolean enabled) {
+        Label label = new Label( parent, getLabelStyle() );
+        label.setLayoutData( layoutData );
+        label.setText( msg );
+        label.setEnabled( enabled );
+        
+        return label;
+    }
+    
+    private Text createText(Composite parent, Object layoutData, Object defaultText, boolean enabled, final InputValidator validator) {
+        Text text = new Text( parent, getTextStyle() );
+        text.setLayoutData( layoutData );
+        if ( defaultText instanceof String ) {
+            text.setText( (String) defaultText );
+        }
+        text.setEnabled( enabled );
+        // TODO : add validation logic
+        
+        return text;
+    }
+    
+    private Text createPasswordText(Composite parent, Object layoutData, Object defaultText, boolean enabled, final InputValidator validator) {
+        Text text = new Text( parent, getPasswordTextStyle() );
+        text.setLayoutData( layoutData );
+        if ( defaultText instanceof char[] ) {
+            text.setText( new String( (char[]) defaultText ) );
+        } else if ( defaultText instanceof Character[] ) {
+            text.setText( ((Character[]) defaultText).toString() );
+        }
+        text.setEnabled( enabled );
+        // TODO : add validation logic
+        
+        return text;
+    }
+    
+    private Button createCheckButton(Composite parent, Object layoutData, final String id, String msg, Object value, boolean enabled) {
+        Button button = new Button( parent, getCheckButtonStyle() );
+        button.setLayoutData( layoutData );
+        button.setText( msg );
+        button.setEnabled( enabled );
+        button.addSelectionListener( new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                enableChildControls( id, ((Button) e.widget).getSelection() );
+            }
+        });
+        button.setSelection( getBoolean( value ) );
+        
+        return button;
+    }
+    
+    
+    /////////////////////////////////////////////////////////////////
+    // model utility
+    
+    /**
+     * Get key by value in the map
+     * @param map
+     * @param value
+     * @return
+     */
+    private <T, E> T getKeyByValue(Map<T, E> map, E value) {
+        Assert.notNull( map );
+        Assert.notNull( value );
+        
+        for ( Entry<T, E> entry : map.entrySet() ) {
+            if ( value.equals( entry.getValue() ) ) {
+                return entry.getKey();
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Get boolean by object value
+     * @param obj
+     * @return If obj is null, return true. if obj is not boolean type, return false. otherwise, return parsed boolean value.
+     */
+    private boolean getBoolean(Object obj) {
+        return ( obj == null ) ? true : Boolean.parseBoolean( String.valueOf( obj ) );
+    }
+    
+    private void enableChildControls(final String id, boolean enabled) {
+        Collection<UserField> childIds = null;
+        for ( UserField field : this.fields ) {
+            childIds = getChildModelById( field, id );
+            if ( !CollectionUtil.isEmpty( childIds ) ) {
+                break;
+            }
+        }
+        
+        if ( !CollectionUtil.isEmpty( childIds ) ) {
+            for ( UserField childId : childIds ) {
+                if ( !childId.canModify() && enabled == true ) {
+                    continue;
+                }
+                
+                Control control = this.controlMap.get( childId.getId() );
+                if ( ! ( control instanceof Composite) ) {
+                    control = control.getParent();
+                }
+                control.setEnabled( enabled );
+            }
+        }
+    }
+    
+    private UserField getModel(Collection<UserField> fields, String id) {
+        for ( UserField field : fields ) {
+            if ( field.getId().equals( id ) ) {
+                return field;
+            }
+            
+            if ( !CollectionUtil.isEmpty( field.getChildren() ) ) {
+                UserField result = getModel( field.getChildren(), id);
+                if ( result != null ) {
+                    return result;
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    private Collection<UserField> getChildModelById(final UserField field, final String id) {
+        Assert.notNull( id );
+        
+        Collection<UserField> children = field.getChildren();
+        if ( CollectionUtil.isEmpty( field.getChildren() )) {
+            return null;
+        }
+        
+        if ( id.equals( field.getId() ) ) {
+            return children;
+        }
+        
+        for ( UserField child : children ) {
+            Collection<UserField> childResult = getChildModelById( child, child.getId() );
+            if ( !CollectionUtil.isEmpty( childResult ) ) {
+                return childResult;
+            }
+        }
+        
+        return null;
+    }
+}