From: Jihoon Song Date: Wed, 14 Nov 2012 07:24:34 +0000 (+0900) Subject: [Title] common-eplugin: added DynamicDialog using UserField model for Prompter X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9f9b6b5d9862764f21853ae33231b137eb0d9246;p=sdk%2Fide%2Fcommon-eplugin.git [Title] common-eplugin: added DynamicDialog using UserField model for Prompter [Desc.] [Issue] Change-Id: I208f75e23c055001693919209c65089009f9d33b --- diff --git a/org.tizen.common/META-INF/MANIFEST.MF b/org.tizen.common/META-INF/MANIFEST.MF index 9378167..a27ca2e 100755 --- a/org.tizen.common/META-INF/MANIFEST.MF +++ b/org.tizen.common/META-INF/MANIFEST.MF @@ -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 index 0000000..97474b2 --- /dev/null +++ b/org.tizen.common/src/org/tizen/common/ui/dialog/DynamicDialog.java @@ -0,0 +1,500 @@ +/* + * Common + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jihoon Song + * + * 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} + */ +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 fields; + + // ID based controls for searching + protected Map controlMap = new HashMap(); + + + ///////////////////////////////////////////////////////////////// + // Constructor + + /** + * Default constructor for dynamic generation + * @param parent parent shell + * @param userFields {@link UserField} + */ + public DynamicDialog(Shell parent, Collection fields) { + super( parent ); + Assert.notNull( fields ); + + this.fields = fields; + } + + public DynamicDialog(IShellProvider parentShell, Collection fields) { + super( parentShell ); + Assert.notNull( fields ); + + this.fields = fields; + } + + /** + * Constructor for dynamic generation using current active shell + * @param userFields {@link UserField} + */ + public DynamicDialog(Collection 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 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 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 getKeyByValue(Map map, E value) { + Assert.notNull( map ); + Assert.notNull( value ); + + for ( Entry 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 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 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 getChildModelById(final UserField field, final String id) { + Assert.notNull( id ); + + Collection children = field.getChildren(); + if ( CollectionUtil.isEmpty( field.getChildren() )) { + return null; + } + + if ( id.equals( field.getId() ) ) { + return children; + } + + for ( UserField child : children ) { + Collection childResult = getChildModelById( child, child.getId() ); + if ( !CollectionUtil.isEmpty( childResult ) ) { + return childResult; + } + } + + return null; + } +}