/* $Id: SwingUIFactory.java 19153 2011-03-30 19:48:40Z linus $ ******************************************************************************* * Copyright (c) 2009-2010 Contributors - see below * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bob Tarling - Post GSOC improvements * Christian L�pez Esp�nola ******************************************************************************* * * Some portions of this file was previously release using the BSD License: */ // Copyright (c) 2008 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.core.propertypanels.ui; import java.util.Collection; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.border.TitledBorder; import org.apache.log4j.Logger; import org.argouml.application.helpers.ResourceLoaderWrapper; import org.argouml.core.propertypanels.model.CheckBoxData; import org.argouml.core.propertypanels.model.ControlData; import org.argouml.core.propertypanels.model.GetterSetterManager; import org.argouml.core.propertypanels.model.PanelData; import org.argouml.i18n.Translator; import org.argouml.model.Model; import org.argouml.ui.ActionCreateContainedModelElement; import org.argouml.uml.ui.ActionDeleteModelElements; import org.argouml.uml.ui.foundation.extension_mechanisms.ActionNewStereotype; import org.tigris.toolbar.ToolBarFactory; /** * Creates the XML Property panels */ class SwingUIFactory { private static final Logger LOG = Logger.getLogger(SwingUIFactory.class); public SwingUIFactory() { } /** * @param target The model element selected * @return A Panel to be added to the main panel * @throws Exception If something goes wrong * @see org.argouml.core.propertypanels.panel.UIFactory#createGUI(java.lang.Object) */ public void createGUI ( final Object target, final JPanel panel) throws Exception { PanelData panelData = XMLPropPanelFactory.getInstance().getPropertyPanelsData( target.getClass()); if (panelData == null) { panel.add(new JLabel("There is no panel configured for " + target.getClass())); LOG.error("No panel found for " + target.getClass()); return; } createLabel(target, panelData, panel); for (ControlData prop : panelData.getProperties()) { try { if ("text".equals(prop.getControlType())) { buildTextboxPanel(panel, target, prop); } else if ("combo".equals(prop.getControlType())) { buildComboPanel(panel, target, prop); } else if ("checkgroup".equals(prop.getControlType())) { buildCheckGroup(panel, target, prop); } else if ("optionbox".equals(prop.getControlType())) { buildOptionBox(panel, target, prop); } else if ("singlerow".equals(prop.getControlType())) { buildSingleRow(panel, target, prop); } else if ("list".equals(prop.getControlType())) { buildList(panel, target, prop); } else if ("textarea".equals(prop.getControlType())) { buildTextArea(panel, target, prop); } else if ("separator".equals(prop.getControlType())) { panel.add(LabelledLayout.getSeparator()); } } catch (Exception e) { String message = "Exception caught building control " + prop.getControlType() + " for property " + prop.getPropertyName() + " on panel for " + target; LOG.error(message, e); try { panel.add(new JLabel(message)); } catch (Exception ex) { throw e; } } } } /** * Create the label with icon and description for the panel. * @param target * @param panel */ private void createLabel( final Object target, final PanelData panelData, final JPanel panel) { final String metaTypeName = Model.getMetaTypes().getName(target); final ToolBarFactory tbf = new ToolBarFactory(new Object[0]); tbf.setRollover(true); final JToolBar tb = tbf.createToolBar(); final String label; if (Model.getFacade().isAPseudostate(target)) { // TODO: We need some way of driving this from panel xml rather // than hard coded test Object pseudostateKind = Model.getFacade().getKind(target); label = Model.getFacade().getName(pseudostateKind); } else { label = metaTypeName; } tb.add(new JLabel(label, ResourceLoaderWrapper.lookupIconResource(label), JLabel.LEFT)); if (!Model.getModelManagementHelper().isReadOnly(target)) { tb.add(new NavigateUpAction(target)); if (panelData.isSiblingNavigation()) { tb.add(new NavigatePreviousAction(target)); tb.add(new NavigateNextAction(target)); } tb.add(new ActionDeleteModelElements()); // We only have this here until we have stereotypes // list on property panel tb.add(new ActionNewStereotype()); addCreateButtons(target, tb, panelData.getNewChildElements()); final Object parent = Model.getFacade().getModelElementContainer(target); addCreateButtons(parent, tb, panelData.getNewSiblingElements()); } panel.add(tb); } /** * Create the actions to create new model elements and add the buttons to * perform those actions to the given toolbar. * @param container The model element that will contain the newly created elements * @param tb The toolbar to contain the buttons. * @param metaTypes The list of model element types for which * actions/buttons are required */ private void addCreateButtons( final Object container, final JToolBar tb, final Collection<Class<?>> metaTypes) { if (container != null) { for (Class<?> metaType : metaTypes) { if (Model.getUmlFactory().isContainmentValid( metaType, container)) { tb.add(new ActionCreateContainedModelElement( metaType, container)); } } } } private void buildTextArea( final JPanel panel, final Object target, final ControlData prop) { // TODO: Why do we need this as well as control? Why is it // instantiated when its not always needed. JPanel p = new JPanel(); final TitledBorder border = new TitledBorder(prop.getPropertyName()); p.setBorder(border); JComponent control = null; final String propertyName = prop.getPropertyName(); final Class<?> type = prop.getType(); if ("initialValue".equals(prop.getPropertyName())) { UMLExpressionModel model = new UMLInitialValueExpressionModel(target); p = new UMLExpressionPanel(model, prop.getPropertyName()); control = p; } else if ("defaultValue".equals(prop.getPropertyName())) { UMLExpressionModel model = new UMLDefaultValueExpressionModel(target); p = new UMLExpressionPanel(model, prop.getPropertyName()); control = p; } else if ("specification".equals(prop.getPropertyName())) { UMLPlainTextDocument document = new UMLOperationSpecificationDocument(prop.getPropertyName(), target); UMLTextArea osta = new UMLTextArea(document); osta.setRows(3); control = new JScrollPane(osta); } else if ("body".equals(propertyName) && type == String.class) { UMLPlainTextDocument document = new UMLCommentBodyDocument(propertyName, target); UMLTextArea text = new UMLTextArea(document); text.setLineWrap(true); text.setRows(5); control = new JScrollPane(text); } else if ("condition".equals(prop.getPropertyName())) { UMLExpressionModel conditionModel = new UMLConditionExpressionModel(target); JTextArea conditionArea = new UMLExpressionBodyField(conditionModel, true); conditionArea.setRows(5); control = new JScrollPane(conditionArea); } else if ("script".equals(prop.getPropertyName())) { UMLExpressionModel scriptModel = new UMLScriptExpressionModel(target); p = new UMLExpressionPanel(scriptModel, prop.getPropertyName()); control = p; } else if ("recurrence".equals(prop.getPropertyName())) { UMLExpressionModel recurrenceModel = new UMLRecurrenceExpressionModel(target); p = new UMLExpressionPanel(recurrenceModel, prop.getPropertyName()); control = p; } else if ("expression".equals(prop.getPropertyName())) { UMLExpressionModel model = new UMLExpressionExpressionModel(target); p = new UMLExpressionPanel(model, prop.getPropertyName()); control = p; } else if ("changeExpression".equals(prop.getPropertyName())) { UMLExpressionModel model = new UMLChangeExpressionModel(target); p = new UMLExpressionPanel(model, prop.getPropertyName()); control = p; } else if ("when".equals(prop.getPropertyName())) { UMLExpressionModel model = new UMLTimeExpressionModel(target); p = new UMLExpressionPanel(model, prop.getPropertyName()); control = p; } if (control != null) { if (control == p) { // if the control is a panel, add it addControl(panel, null, control, target); } else { // if not, it is a control and must be labeled... addControl(panel, Translator.localize(prop.getLabel()), control, target); } } else { final GetterSetterManager getterSetter = GetterSetterManager.getGetterSetter(prop.getType()); if (getterSetter.contains(propertyName)) { ExpressionModel model = new ExpressionModel(propertyName, prop.getTypes().get(0), target, getterSetter); final JTextField languageField = new ExpressionLanguageField(model); addControl( panel, Translator.localize("label.language"), languageField, target); control = new JScrollPane(new ExpressionBodyField(model)); addControl(panel, null, control, target); } } } private void buildSingleRow(JPanel panel, Object target, ControlData prop) { final SingleListFactory factory = new SingleListFactory(); final JComponent pane = factory.createComponent(target, prop.getPropertyName(), prop.getTypes()); if (pane != null) { addControl(panel, Translator.localize(prop.getLabel()), pane, target); } } private void buildList( final JPanel panel, Object target, final ControlData prop) { final ListFactory factory = new ListFactory(); final JComponent list = factory.createComponent(target, prop.getPropertyName(), prop.getTypes()); if (list != null) { addControl(panel, Translator.localize(prop.getLabel()), list, target); } } /** * @param target The target of the panel * @param prop The XML data that contains the information * of the options. * @return a radio button panel with the options */ private void buildOptionBox(JPanel panel, Object target, ControlData prop) { final String propertyName = prop.getPropertyName(); final GetterSetterManager getterSetter = GetterSetterManager.getGetterSetter(prop.getType()); if (getterSetter.contains(propertyName)) { JPanel control = new RadioButtonPanel( target, propertyName, true, getterSetter); addControl(panel, null, control, target); } } /** * @param target The target of the checkbox group * @param prop The XML data that contains the information * of the checkboxes. * @return a panel that contains the checkboxes */ private void buildCheckGroup( final JPanel panel, final Object target, final ControlData prop) { JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); TitledBorder border = new TitledBorder(prop.getPropertyName()); p.setBorder(border); if ("modifiers".equals(prop.getPropertyName())) { for (CheckBoxData data : prop.getCheckboxes()) { buildCheckBox(p, target, data); } } addControl(panel, null, p, target); } private void buildCheckBox( final JPanel panel, final Object target, final CheckBoxData prop) { final String propertyName = prop.getPropertyName(); final GetterSetterManager getterSetter = GetterSetterManager.getGetterSetter(prop.getType()); final String label = Translator.localize(prop.getLabel()); if (getterSetter.contains(propertyName)) { final CheckBox cb = new CheckBox(label, target, propertyName, getterSetter); if (Model.getModelManagementHelper().isReadOnly(target)) { cb.setEnabled(false); } panel.add(cb); } } /** * @param panel The panel where the controls will be added. * @param target The target of the panel * @param prop The XML data that contains the information * of the combo. * @return a combo panel */ private void buildComboPanel( final JPanel panel, final Object target, final ControlData prop) { JComponent comp = null; final String propertyName = prop.getPropertyName(); if ("namespace".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLModelElementNamespaceComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLSearchableComboBox( model, model.getAction(), true); comp = new UMLComboBoxNavigator( Translator.localize( "label.namespace.navigate.tooltip"), combo); } else if ("type".equals(prop.getPropertyName())) { final UMLComboBoxModel model; if (Model.getFacade().isATemplateParameter(target)) { model = new UMLStructuralFeatureTypeComboBoxModel( propertyName, Model.getFacade().getParameter(target)); } else { model = new UMLStructuralFeatureTypeComboBoxModel( propertyName, target); } comp = new UMLComboBox(model); } else if ("base".equals(prop.getPropertyName())) { if (Model.getFacade().isAAssociationRole(target)) { final UMLComboBoxModel model = new UMLAssociationRoleBaseComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLSearchableComboBox( model, model.getAction(), true); comp = new UMLComboBoxNavigator(Translator.localize( "label.association.navigate.tooltip"), combo); } else { // } } else if ("powertype".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLGeneralizationPowertypeComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLComboBox( model); comp = combo; } else if ("multiplicity".equals(prop.getPropertyName())) { final UMLMultiplicityPanel mPanel = new UMLMultiplicityPanel(propertyName, target); comp = mPanel; } else if ("activator".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLMessageActivatorComboBoxModel(propertyName, target); final JComboBox combo = new UMLMessageActivatorComboBox(model, model.getAction()); comp = combo; } else if ("operation".equals(prop.getPropertyName())) { if (Model.getFacade().isACallEvent(target)) { UMLComboBoxModel model = new UMLCallEventOperationComboBoxModel(propertyName, target); UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "label.operation.navigate.tooltip"), combo); } else { final UMLComboBoxModel model = new UMLCallActionOperationComboBoxModel(propertyName, target); UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "label.operation.navigate.tooltip"), combo); } } else if ("classifier".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLComponentInstanceClassifierComboBoxModel(propertyName, target); UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "label.component-instance.navigate.tooltip"), combo); } else if ("representedClassifier".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLCollaborationRepresentedClassifierComboBoxModel(propertyName, target); UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "label.represented-classifier.navigate.tooltip"), combo); } else if ("representedOperation".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLCollaborationRepresentedOperationComboBoxModel(propertyName, target); UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "label.represented-operation.navigate.tooltip"), combo); } else if ("context".equals(prop.getPropertyName())) { final UMLComboBoxModel model; if (Model.getFacade().isAActivityGraph(target)) { model = new UMLActivityGraphContextComboBoxModel(propertyName, target); } else { model = new UMLStateMachineContextComboBoxModel(propertyName, target); } UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "label.context.navigate.tooltip"), combo); } else if ("association".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLLinkAssociationComboBoxModel(propertyName, target); comp = new UMLComboBoxNavigator(Translator.localize( "label.association.navigate.tooltip"), new UMLSearchableComboBox(model, model.getAction(), true)); } else if ("participant".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLAssociationEndTypeComboBoxModel(propertyName, target); comp = new UMLComboBox(model, true); } else if ("submachine".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLSubmachineStateComboBoxModel(propertyName, target); final UMLComboBox submachineBox = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "tooltip.nav-submachine"), submachineBox); } else if ("referenceState".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLStubStateComboBoxModel(propertyName, target); final UMLComboBox referencestateBox = new UMLComboBox(model); comp = new UMLComboBoxNavigator(Translator.localize( "tooltip.nav-stubstate"), referencestateBox); } else if ("tagType".equals(prop.getPropertyName())) { UMLComboBoxModel model = new UMLMetaClassComboBoxModel(propertyName, target); final UMLComboBox typeComboBox = new UMLComboBox(model); comp = new UMLComboBoxNavigator( Translator.localize("label.type.navigate.tooltip"), typeComboBox); // TODO: Why is this disabled always? comp.setEnabled(false); } else if ("parameter".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLTemplateParameterParameterComboBoxModel(target); final UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator( Translator.localize("label.type.navigate.tooltip"), combo); } else if ("defaultElement".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLTemplateParameterDefaultElementComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator( Translator.localize("label.type.navigate.tooltip"), combo); } else if ("signal".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLSignalComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator( Translator.localize("label.type.navigate.tooltip"), combo); } else if ("trigger".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLTransitionTriggerComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator( Translator.localize("label.type.navigate.tooltip"), combo); } else if ("specification".equals(prop.getPropertyName())) { final UMLComboBoxModel model = new UMLMethodSpecificationComboBoxModel(propertyName, target); final UMLComboBox combo = new UMLComboBox(model); comp = new UMLComboBoxNavigator( Translator.localize("label.type.navigate.tooltip"), combo); } if (comp != null) { addControl(panel, Translator.localize(prop.getLabel()), comp, target); } } /** * @param panel a panel with a labelled text field * @param target The target of the panel * @param prop The XML data that contains the information * of the options. */ private void buildTextboxPanel(JPanel panel, Object target, ControlData prop) { UMLPlainTextDocument document = null; if ("name".equals(prop.getPropertyName())) { if (Model.getFacade().isATemplateParameter(target)) { target = Model.getFacade().getParameter(target); } document = new UMLModelElementNameDocument(prop.getPropertyName(), target); } else if ("discriminator".equals(prop.getPropertyName())) { document = new UMLDiscriminatorNameDocument(prop.getPropertyName(), target); } else if ("location".equals(prop.getPropertyName())) { document = new UMLExtensionPointLocationDocument(prop.getPropertyName(), target); } else if ("bound".equals(prop.getPropertyName())) { document = new UMLSynchStateBoundDocument(prop.getPropertyName(), target); } if (document != null) { JTextField tfield = new UMLTextField(document); addControl(panel, Translator.localize(prop.getLabel()), tfield, target); } } private void addControl( final JPanel panel, final String text, final JComponent component, final Object target) { if (Model.getModelManagementHelper().isReadOnly(target)) { component.setEnabled(false); } LabelledComponent lc = new LabelledComponent(text, component); panel.add(lc); } }