Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » scout » Adding dynamic UI elements in scout(Is it possible to dynamically add new elements to a UI which was already rendered?)
Adding dynamic UI elements in scout [message #1232430] Thu, 16 January 2014 18:27 Go to next message
André Morais is currently offline André Morais
Messages: 9
Registered: December 2013
Junior Member
Hi,

I've been looking for information about dynamic UI behavior in Scout as I'm working in a complex RCP application with dynamic UI events that is being migrated to Scout.
However, I've tried to add more form fields to a form already initialized but it did not worked.

I've read a few information and also some older posts where it seem it was not possible to allow this kind of behavior.

Is there any alternative or any other approach that is missing me?


Regards,

André
Re: Adding dynamic UI elements in scout [message #1234688 is a reply to message #1232430] Wed, 22 January 2014 10:30 Go to previous messageGo to next message
João Rebelo is currently offline João Rebelo
Messages: 26
Registered: December 2013
Junior Member
Hi,

All that we've been seeing so far is declaring classes that I would guess Scout will somehow instantiate in runtime to generate the GUI.
It would be interesting that the developer could also conditionally (by some event / action) instantiate new objects of a previously created form, and add them to, for example a AbstractWrappedFormField?

Is this possible in Scout?

(I would imagine that this is somewhat what Scout is doing internally at the UI Thread equivalent?)

Regards,
João
Re: Adding dynamic UI elements in scout [message #1235820 is a reply to message #1234688] Sat, 25 January 2014 06:19 Go to previous messageGo to next message
Claudio Guglielmo is currently offline Claudio Guglielmo
Messages: 126
Registered: March 2010
Senior Member
Hi guys

A form initializes its fields on creation time. During that time you can inject custom fields using injectFields as explained here here. Afterwards you cannot add or remove fields, you can set them to visible / invisible though.

Another approach would be to use an editable table (set getConfiguredEditable of the columns to true) or to use a wrapped form field as João suggests.

-
Claudio
Re: Adding dynamic UI elements in scout [message #1384258 is a reply to message #1235820] Wed, 28 May 2014 10:42 Go to previous message
João Rebelo is currently offline João Rebelo
Messages: 26
Registered: December 2013
Junior Member
Hi,

We would like to share a solution for this issue! Actually it's possible to extend Scout so that we can indeed have a dynamic Group Box!
Allow me to demonstrate:

	/**
	 * Add new field to the group box 
	 * 
	 * @param theFormField the form field
	 */
	public void addField(IFormField theFormField) {


		initNewField(theFormField);
		rebuildFieldGrid();
		setNewField(theFormField);
	}
	
	private void initNewField(IFormField theFormField) {

		try {

			theFormField.setParentFieldInternal(this);
			myField.setFormInternal(this.getForm());
			theFormField.initField();

			AbstractCompositeField anAbstractCompositeField = this;

			Field allFields = AbstractCompositeField.class.getDeclaredField("m_fields");
			allFields.setAccessible(true);

			IFormField[] m_fields = Arrays.copyOf(getFields(), getFields().length + 1);
			m_fields[getFields().length] = theFormField;
			allFields.set(anAbstractCompositeField, m_fields);

		}
		catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException theException) {
			LOG.error("Not Possible to Access SuperClass AbstractCompositeField m_fields", theException);
			throw new RuntimeException(theException);
		}
		catch (ProcessingException theException) {
			LOG.error("Error processing abstractQueryFilterDesignerField ", theException);
			throw new RuntimeException(theException);
		}

	}
	
	
	/**
	 * This method sends the new Form Field to be created in the UI layer
	 * 
	 * @param theNewFormField the new Form Field
	 */
	protected void setNewField(IFormField theNewFormField) {
		propertySupport.setProperty(PROP_NEW_FIELD, theNewFormField);
	}
	


So this is our extension to the GroupBox. The trick here is that we have to access the private m_fields variable to add our own field, and then call the rebuildFieldGrid method.
Speaking in UI terms, this would be more or less equivalent to calling a "layout(true, true)" after adding a field in a Composite

Also very important detail is that each Field must be setted with:
the correct parent field,
the correct form where he belongs,
and finally be initialized (initField method).

With this in place, to add a new Field would be as easy as:

	MyField myField = new MyField();
	myDynamicGroupBox.addField(myField);


Same kind of solution can be used to remove elements, add multiple elements, re-sort the current elements (moving them in m_fields list), and so on.

Done with the modelling part we now need to review the rendering side of it. We've actually implemented renderings for SWT and RAP.
Follows the SWT implementation:

	/**
	 * The Group Box Composite where fields are added.
	 */
	protected Composite m_swtBodyPart;

	private ScrolledFormEx m_scrolledForm;
	
	/**
	 * On initialization we'll need to get access to the composite where all fields are added in Scout.
	 * Then we need to process the fields that might already have been dynamically added before the UI rendering initialization
	 */
	@Override
	protected void initializeSwt(Composite theParent) {
		super.initializeSwt(theParent);

		try {
			Field aComposite = SwtScoutGroupBox.class.getDeclaredField("m_swtBodyPart");
			aComposite.setAccessible(true);

			Composite aCompositeToAdd = (Composite) aComposite.get(this);
		
			setM_swtBodyPart(aCompositeToAdd);

			//Assumes using scrolled forms 
			m_scrolledForm = (ScrolledFormEx) theParent.getParent().getParent();

			// FIELDS:
			List<IFormField> allFields = ((IFormField) getScoutObject()).getFields();
			for (IFormField aField : allFields) {
				addNewFieldForm(aField);
			}

		}
		catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException theException) {
			LOG.error("Not Possible to Access SuperClass SwtScoutGroupBox m_swtBodyPart", theException);
			throw new RuntimeException(theException);
		}
		catch (ClassCastException theException) {
			LOG.error("No scroll found in parent hierarchy ! ", theException);
			throw new RuntimeException(theException);
		}
	}
	
	@Override
	protected void handleScoutPropertyChange(String theName, Object theValue) {
		if (theName.equals(PROP_NEW_FIELD)) {
			if (theValue != null && (theValue instanceof IFormField)) {
				addNewFieldForm((IFormField) theValue);
				refresh();
			}
		}
		else {
			super.handleScoutPropertyChange(theName, theValue);
		}
	}
	
	/**
	 * Add new field form.
	 * Notice the Scout Field Grid Data that needs to be created so that all Scout layout properties are correctly used.
	 * @param theField the IFormField
	 */
	public void addNewFieldForm(IFormField theField) {
		ISwtScoutFormField aSwtScoutComposite = getEnvironment().createFormField(m_swtBodyPart, theField);
		SwtScoutFormFieldGridData aLayoutData = new SwtScoutFormFieldGridData(theField);
		aSwtScoutComposite.getSwtContainer().setLayoutData(aLayoutData);

		//map our dynamic fields into the its models - Useful for removal afterwards
		fieldMap.put(theField, aSwtScoutComposite);
	}
	
	
	/**
	 * Refresh this box
	 * If not using a scrolled form then some kind of parent layout or refresh should be used
	 */
	protected void refresh() {
		m_scrolledForm.reflow(true);
	}


And the RAP implementation with some changes:

	@Override
	protected void initializeUi(Composite theParent) {
		super.initializeUi(theParent);

		try {
			Field aComposite = RwtScoutGroupBox.class.getDeclaredField("m_bodyPart");
			aComposite.setAccessible(true);
			setM_bodyPart((Composite) aComposite.get(this));

			//Assumes using scrolled forms 
			m_scrolledComposite = (ScrolledComposite) theParent.getParent();
			

			// FIELDS:
			List<IQueryFilterField> allFiltersFields = ((AbstractQueryFilterDesignerBox) getScoutObject()).getFilterFieldList();
			for (IQueryFilterField aField : allFiltersFields) {
				addNewFieldForm((IFormField) aField);
			}

		}
		catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException theException) {
			LOG.error("Not Possible to Access SuperClass SwtScoutGroupBox m_swtBodyPart", theException);
			throw new RuntimeException(theException);
		}
		catch (ClassCastException theException) {
			LOG.error("No scroll found in parent hierarchy ! ", theException);
			throw new RuntimeException(theException);
		}
	}

	
	/**
	 * Add new field form
	 * 
	 * @param theField the IFormField
	 */
	public void addNewFieldForm(IFormField theField) {
		IRwtScoutFormField aRwtScoutComposite = getUiEnvironment().createFormField(m_bodyPart, theField);
		RwtScoutFormFieldGridData aLayoutData = new RwtScoutFormFieldGridData(theField);
		aRwtScoutComposite.getUiContainer().setLayoutData(aLayoutData);


		fieldMap.put(theField, aRwtScoutComposite);
	}
	
	private void refresh() {
		if (m_scrolledComposite != null) {

			int aReceiverBorderWidth;
			try {
				aReceiverBorderWidth = m_scrolledComposite.getBorderWidth();
			}
			catch (Exception theException) {
				aReceiverBorderWidth = SWT.DEFAULT;
				LOG.error("Not possible to calculate the receiver border width.", theException);
			}

			m_scrolledComposite.setMinSize(m_scrolledComposite.computeSize(aReceiverBorderWidth, SWT.DEFAULT));
			m_scrolledComposite.layout(true, true);
		}

		getUiContainer().layout();
		if (parentDynamicBox != null) {
			parentDynamicBox.refresh();
		}
	}
	
		@Override
	protected void handleScoutPropertyChange(String theName, Object theValue) {
		if (theName.equals(IQueryFilterDesignerBox.PROP_NEW_FIELD)) {
			if (theValue != null && (theValue instanceof IFormField)) {
				addNewFieldForm((IFormField) theValue);
				refresh();
			}
		}
		else {
			super.handleScoutPropertyChange(theName, theValue);
		}
	}


Essentially the only rendering differences would be on the way the refresh is done, but very similar code in both solutions.

Just a warning/notice: Keep in mind that this solution makes use of Scout internals so it might break if some internal logic changes or variables are simply renamed.

Regards,
João Rebelo
Previous Topic:Nebula NatTable used in a Scout application
Next Topic:MessageBox shows with quite a delay
Goto Forum:
  


Current Time: Sat Aug 02 02:44:33 EDT 2014

Powered by FUDForum. Page generated in 0.01916 seconds