/* * Copyright (c) 2005,2009 Declarative Engineering LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Declarative Engineering LLC * verson 1 which accompanies this distribution, and is available at * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt */ package com.foundation.view.swt; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.widgets.Layout; import com.common.util.ICollection; import com.common.util.IIterator; import com.common.util.IList; import com.common.util.LiteList; import com.foundation.controller.ViewController; import com.foundation.util.IInlineCollectionObservable; import com.foundation.util.IInlineCollectionObserver; import com.foundation.util.IInlineIndexedCollectionObservable; import com.foundation.util.IInlineIndexedCollectionObserver; import com.foundation.view.IEventAssociation; import com.foundation.view.SingleAssociationContainer; import com.foundation.view.SingleResourceAssociation; import com.foundation.view.swt.util.SwtUtilities; /* * Displays components in a stack such that only one component is visible at a time. */ public class StackViewer extends Container implements IInlineIndexedCollectionObserver, IInlineCollectionObserver { /** The association that results in a collection of view controllers. */ private SingleResourceAssociation views = null; /** The association that tracks which view is being displayed. */ private SingleResourceAssociation visibleView = null; /** The previous collection of view controllers. */ private IList viewControllers = new LiteList(1, 15); /** Temporarily suspends processing of events fired by registered collections. */ private boolean suspendCollectionEvents = false; /** * StackViewer constructor. * @param parent A composite control which will be the parent of the new instance (cannot be null). * @param name The unique component name. * @param style The style of control to construct. * @see #STYLE_NO_BACKGROUND * @see #STYLE_NO_FOCUS * @see #STYLE_NO_MERGE_PAINTS * @see #STYLE_NO_REDRAW_RESIZE * @see #STYLE_NO_RADIO_GROUP * @see #STYLE_H_SCROLL * @see #STYLE_V_SCROLL * @see #STYLE_BORDER * @see #STYLE_LEFT_TO_RIGHT * @see #STYLE_RIGHT_TO_LEFT */ public StackViewer(Container parent, String name, int style) { super(parent, name, style); this.views = new SingleResourceAssociation(this, this, getViewContext(), SingleResourceAssociation.TYPE_OBJECT, false, null); this.visibleView = new SingleResourceAssociation(this, this, getViewContext(), SingleResourceAssociation.TYPE_OBJECT, false, null); }//StackViewer()// /* (non-Javadoc) * @see com.foundation.view.swt.AbstractComponent#initializeControl(int) */ protected void initializeControl(int style, Object data) { setSwtWidget(new org.eclipse.swt.widgets.Composite(((Container) getContainer()).getSwtParent(), style)); getSwtWidget().setData(this); getSwtComposite().setLayout(new StackLayout()); }//initializeControl()// /** * Gets the stack layout used with the wizard. * @return The wizard's stack layout. */ protected StackLayout getLayout() { return (StackLayout) getSwtComposite().getLayout(); }//getLayout()// /* (non-Javadoc) * @see com.foundation.view.swt.Container#setLayout(org.eclipse.swt.widgets.Layout) */ public void setLayout(Layout layout) { //Does nothing. Layouts are not allowed here.// }//setLayout()// /** * Gets the SWT composite that represents this panel. * @return The SWT composite providing visualization for this panel. */ public org.eclipse.swt.widgets.Composite getSwtComposite() { return (org.eclipse.swt.widgets.Composite) getSwtControl(); }//getSwtComposite()// /** * Sets the association container used to access the views in the stack. * @param container The views association metadata. */ public void setViewsAssociation(SingleAssociationContainer container) { verifyThread(); this.views.setAssociations(container); }//setViewsAssociation()// /** * Sets the association container used to access the visible view. * @param container The visible view association metadata. */ public void setVisibleViewAssociation(SingleAssociationContainer container) { verifyThread(); this.visibleView.setAssociations(container); }//setVisibleViewAssociation()// /* (non-Javadoc) * @see com.foundation.view.swt.AbstractComponent#internalOnEventFired(com.foundation.view.swt.IEventAssociation, java.lang.Object[]) */ protected void internalOnEventFired(IEventAssociation eventAssociation, Object[] eventArguments) { }//internalOnEventFired()// /* (non-Javadoc) * @see com.foundation.view.swt.AbstractComponent#internalViewInitialize() */ protected void internalViewInitialize() { views.initialize(); visibleView.initialize(); super.internalViewInitialize(); }//internalViewInitialize()// /* (non-Javadoc) * @see com.foundation.view.swt.AbstractComponent#internalViewRelease() */ protected void internalViewRelease() { super.internalViewRelease(); views.release(); visibleView.release(); for(int index = 0; index < viewControllers.getSize(); index++) { ((ViewController) viewControllers.get(index)).close(); }//for// }//internalViewRelease()// /* (non-Javadoc) * @see com.foundation.view.swt.AbstractComponent#internalViewRefresh() */ protected void internalViewRefresh() { super.internalViewRefresh(); internalRefreshViews(); internalRefreshVisibleView(); }//internalViewRefresh()// /** * Refreshes the currently visible component. */ protected void internalRefreshViews() { Object oldValue = views.getValue(); if(views.refresh()) { stopRendering(); try { Object newValue = views.getValue(); //Remove listeners from the old value.// if(oldValue instanceof IInlineIndexedCollectionObservable) { ((IInlineIndexedCollectionObservable) oldValue).removeCollectionObserver(this); }//if// else if(oldValue instanceof IInlineCollectionObservable) { ((IInlineCollectionObservable) oldValue).removeCollectionObserver(this); }//else if// //Close the old view controllers.// for(int index = 0; index < viewControllers.getSize(); index++) { ((ViewController) viewControllers.get(index)).close(); }//for// viewControllers.removeAll(); //If the new value is a collection or object then add and remove pages as required, and add listeners as required.// if(newValue instanceof ICollection) { IIterator iterator = ((ICollection) newValue).iterator(); //Add tabs for all the view controllers.// while(iterator.hasNext()) { Object next = iterator.next(); //Ignore non-view controller objects.// if(next instanceof ViewController) { ViewController controller = (ViewController) next; controller.openPartial(this, getViewContext()); }//if// else { throw new RuntimeException("Expecting a view controller."); }//else// }//while// //Add the controllers to the list of view controllers.// viewControllers.addAll((ICollection) newValue); //Prevent collection events from notifying us of existing items in the collection.// suspendCollectionEvents = true; //Add a listener to the collection so we get change events.// if(newValue instanceof IInlineIndexedCollectionObservable) { ((IInlineIndexedCollectionObservable) newValue).addCollectionObserver(this); }//if// else if(newValue instanceof IInlineCollectionObservable) { ((IInlineCollectionObservable) newValue).addCollectionObserver(this); }//else if// //Re-enable the collection events.// suspendCollectionEvents = false; }//if// else if(newValue instanceof ViewController) { ViewController controller = (ViewController) newValue; controller.openPartial(this, getViewContext()); //Add the one controller to the list of view controllers.// viewControllers.add(controller); }//else if// }//try// finally { startRendering(); }//finally// }//if// }//internalRefreshViews()// /** * Refreshes the currently visible component. */ protected void internalRefreshVisibleView() { if(visibleView.refresh()) { Object view = (Object) visibleView.getValue(); int index = viewControllers.getIndexOf(view); if(index >= 0) { ((StackLayout) getSwtComposite().getLayout()).topControl = getSwtComposite().getChildren()[index]; getSwtComposite().layout(true, false); }//if// }//if// }//internalRefreshVisibleView()// /* (non-Javadoc) * @see com.foundation.view.swt.AbstractComponent#internalViewSynchronize() */ protected void internalViewSynchronize() { //Since the page can only be set manually, this method should do nothing.// super.internalViewSynchronize(); }//internalViewSynchronize()// /* (non-Javadoc) * @see com.foundation.view.swt.Component#internalOnValueChanged(com.foundation.view.SingleResourceAssociation, int) */ protected void internalOnValueChanged(SingleResourceAssociation association, int flags) { if(association == visibleView) { internalRefreshVisibleView(); }//if// else if(association == views) { internalRefreshViews(); }//else if// else { super.internalOnValueChanged(association, flags); }//else// }//internalOnValueChanged()// /* (non-Javadoc) * @see com.foundation.util.IInlineIndexedCollectionObserver#startChanges(int) */ public void startChanges(int changeCount) { startRendering(); }//startChanges()// /* (non-Javadoc) * @see com.foundation.util.IInlineIndexedCollectionObserver#stopChanges() */ public void stopChanges() { stopRendering(); }//stopChanges()// /* (non-Javadoc) * @see com.foundation.util.IInlineCollectionObserver#valueAdded(java.lang.Object) */ public void valueAdded(Object value) { if((!suspendCollectionEvents) && (value instanceof ViewController)) { viewControllers.add(value); ((ViewController) value).openPartial(this, getViewContext()); }//if// }//valueAdded()// /* (non-Javadoc) * @see com.foundation.util.IInlineIndexedCollectionObserver#valueAdded(java.lang.Object, int) */ public void valueAdded(Object value, int index) { valueAdded(value); }//valueAdded()// /* (non-Javadoc) * @see com.foundation.util.IInlineCollectionObserver#valueRemoved(java.lang.Object) */ public void valueRemoved(Object value) { if((!suspendCollectionEvents) && (viewControllers.remove(value))) { ((ViewController) value).close(); }//if// }//valueRemoved()// /* (non-Javadoc) * @see com.foundation.util.IInlineIndexedCollectionObserver#valueRemoved(java.lang.Object, int) */ public void valueRemoved(Object value, int index) { valueRemoved(value); }//valueRemoved()// /* (non-Javadoc) * @see com.foundation.util.IInlineIndexedCollectionObserver#removingAll() */ public void removingAll() { if(!suspendCollectionEvents) { IIterator iterator = viewControllers.iterator(); startChanges(viewControllers.getSize()); try { while(iterator.hasNext()) { valueRemoved(iterator.next()); }//while// }//try// finally { stopChanges(); }//finally// }//if// }//removingAll()// /* (non-Javadoc) * @see com.foundation.util.IInlineIndexedCollectionObserver#valuesSorted(int[]) */ public void valuesSorted(int[] mapping) { //Does nothing.// }//valuesSorted()// }//StackViewer//