/*
* #!
* Ontopoly Editor
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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.
* !#
*/
package ontopoly.components;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import net.ontopia.utils.ObjectUtils;
import net.ontopia.utils.OntopiaRuntimeException;
import ontopoly.jquery.DraggableBehavior;
import ontopoly.jquery.DroppableBehavior;
import ontopoly.model.AssociationField;
import ontopoly.model.AssociationType;
import ontopoly.model.Cardinality;
import ontopoly.model.FieldAssignment;
import ontopoly.model.FieldDefinition;
import ontopoly.model.OccurrenceField;
import ontopoly.model.RoleField;
import ontopoly.model.Topic;
import ontopoly.model.TopicType;
import ontopoly.models.FieldAssignmentModel;
import ontopoly.models.FieldDefinitionModel;
import ontopoly.models.MutableLoadableDetachableModel;
import ontopoly.models.TopicTypeModel;
import ontopoly.pages.InstancePage;
import ontopoly.utils.TopicChoiceRenderer;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
public abstract class FieldsEditorExistingPanel extends Panel {
private boolean readonly;
public FieldsEditorExistingPanel(String id, final TopicTypeModel topicTypeModel, final FieldAssignmentModel fieldAssignmentModel, boolean readonly) {
super(id);
this.readonly = readonly;
FieldAssignment fieldAssignment = fieldAssignmentModel.getFieldAssignment();
WebMarkupContainer container = new WebMarkupContainer("field", fieldAssignmentModel);
add(container);
OntopolyImage icon = new OntopolyImage("icon", "dnd.gif", new ResourceModel("icon.dnd.reorder"));
icon.setVisible(!readonly);
container.add(icon);
FieldDefinition fieldDefinition = fieldAssignment.getFieldDefinition();
final FieldDefinitionModel fieldDefinitionModel = new FieldDefinitionModel(fieldDefinition);
container.add(new FieldDefinitionLabel("fieldLabel", fieldDefinitionModel) {
@Override
protected boolean isFieldDefinitionLinkEnabled(Topic topic) {
return true;
}
@Override
protected boolean isOntologyTypeLinkEnabled(Topic topic) {
return true;
}
});
Component fieldType = getFieldType("valueType", fieldAssignmentModel.getFieldAssignment().getFieldDefinition());
fieldType.setRenderBodyOnly(true);
container.add(fieldType);
Component cardinalityComponent = getCardinality("cardinality", fieldAssignmentModel);
cardinalityComponent.setEnabled(!readonly);
container.add(cardinalityComponent);
// drag and drop
if (!readonly) {
String dndId = "fields_" + topicTypeModel.getTopicType().getId();
container.add(new DraggableBehavior(dndId));
container.add(new DroppableBehavior(dndId) {
@Override
protected MarkupContainer getDropContainer() {
return FieldsEditorExistingPanel.this.getParent().getParent();
}
@Override
protected void onDrop(Component component, AjaxRequestTarget target) {
FieldAssignmentModel fam_dg = (FieldAssignmentModel)component.getDefaultModel();
FieldAssignmentModel fam_do = (FieldAssignmentModel)getComponent().getDefaultModel();
FieldAssignment fa_dg = fam_dg.getFieldAssignment();
FieldAssignment fa_do = fam_do.getFieldAssignment();
fa_do.moveAfter(fa_dg);
FieldsEditorExistingPanel.this.onMoveAfter(fam_dg, fam_do, target);
}
});
}
TopicType topicType = topicTypeModel.getTopicType();
TopicType declaredTopicType = fieldAssignmentModel.getFieldAssignment().getDeclaredTopicType();
if (ObjectUtils.equals(topicType, declaredTopicType)) {
OntopolyImageLink button = new OntopolyImageLink("button", "remove-value.gif", new ResourceModel("icon.remove.field")) {
@Override
public void onClick(AjaxRequestTarget target) {
FieldsEditorExistingPanel.this.onRemove(fieldAssignmentModel, target);
}
@Override
public boolean isVisible() {
return !FieldsEditorExistingPanel.this.readonly;
//! || (fieldDefinitionModel.getFieldDefinition().isSystemTopic() && ((OntopolySession)Session.get()).isAdministrationEnabled());
}
};
container.add(button);
} else {
OntopolyImageLink button = new OntopolyImageLink("button", "goto.gif", new ResourceModel("icon.goto.assigning-type")) {
@Override
public void onClick(AjaxRequestTarget target) {
TopicType declaredTopicType = fieldAssignmentModel.getFieldAssignment().getDeclaredTopicType();
Map<String,String> pageParametersMap = new HashMap<String,String>(3);
pageParametersMap.put("topicMapId", declaredTopicType.getTopicMap().getId());
pageParametersMap.put("topicId", declaredTopicType.getId());
pageParametersMap.put("ontology", "true");
setResponsePage(InstancePage.class, new PageParameters(pageParametersMap));
}
};
container.add(button);
}
}
protected abstract void onMoveAfter(FieldAssignmentModel fam_dg, FieldAssignmentModel fam_do, AjaxRequestTarget target);
protected abstract void onRemove(FieldAssignmentModel fam, AjaxRequestTarget target);
static Component getFieldType(String id, FieldDefinition fieldDefinition) {
switch (fieldDefinition.getFieldType()) {
case FieldDefinition.FIELD_TYPE_ROLE: {
TopicType tt = null;
RoleField rf = (RoleField)fieldDefinition;
AssociationField afield = rf.getAssociationField();
List<RoleField> fields = afield.getFieldsForRoles();
int numberOfRoles = fields.size();
String fieldTypeAsString = "";
if (numberOfRoles == 1) { // unary
return new Label(id, new ResourceModel("FieldsEditorExistingPanel.valuetype.unary"));
} else if(numberOfRoles == 2) { // binary
AssociationType at = rf.getAssociationType();
if (at.isSymmetric()) { // symmetric
Collection<TopicType> allowedValueTypes = rf.getDeclaredPlayerTypes();
if (allowedValueTypes.size() == 1) { // only one allowed player
Iterator<TopicType> it = allowedValueTypes.iterator();
// It's only one element in the list
while (it.hasNext()) {
tt = it.next();
fieldTypeAsString = tt.getName();
}
} else { // more than one allowed player
return new Label(id, new ResourceModel("FieldsEditorExistingPanel.valuetype.many")).add(new SimpleAttributeModifier("title", getAllowedPlayerNames(rf))).add(new SimpleAttributeModifier("class", "italic"));
}
} else { // binary
Iterator<RoleField> it = fields.iterator();
while (it.hasNext()) {
RoleField rf2 = it.next();
if (!rf.equals(rf2)) { // the other association field
Collection<TopicType> allowedValueTypes = rf2.getDeclaredPlayerTypes();
if (allowedValueTypes.size() == 1) { // only one allowed player
Iterator<TopicType> it2 = allowedValueTypes.iterator();
// It's only one element in the list
while (it2.hasNext()) {
tt = (TopicType)it2.next();
fieldTypeAsString = tt.getName();
}
}
else { // more than one allowed player
return new Label(id, new ResourceModel("FieldsEditorExistingPanel.valuetype.many")).add(new SimpleAttributeModifier("title", getAllowedPlayerNames(rf))).add(new SimpleAttributeModifier("class", "italic"));
}
}
}
}
} else if(numberOfRoles > 2) { // n-ary
return new Label(id, new ResourceModel("FieldsEditorExistingPanel.valuetype.many")).add(new SimpleAttributeModifier("title", getAllowedPlayerNames(rf))).add(new SimpleAttributeModifier("class", "italic"));
}
// Create link if the association field is for a binary association
// with only one topic type on the other side of the association.
PageParameters params = new PageParameters();
params.put("topicMapId", fieldDefinition.getTopicMap().getId());
params.put("ontology", "true");
if (tt != null)
params.put("topicId", tt.getId());
return new OntopolyBookmarkablePageLink(id, InstancePage.class, params, fieldTypeAsString);
}
case FieldDefinition.FIELD_TYPE_IDENTITY: {
return new Label(id, new ResourceModel("FieldsEditorExistingPanel.valuetype.uri"));
}
case FieldDefinition.FIELD_TYPE_NAME: {
return new Label(id, new ResourceModel("FieldsEditorExistingPanel.valuetype.name"));
}
case FieldDefinition.FIELD_TYPE_OCCURRENCE: {
return new Label(id, ((OccurrenceField)fieldDefinition).getDataType().getName());
}
case FieldDefinition.FIELD_TYPE_QUERY: {
return new Label(id, new Model<String>("Query"));
}
default:
throw new OntopiaRuntimeException("Unknown field definition: " + fieldDefinition.getFieldType());
}
}
private static String getAllowedPlayerNames(RoleField rf) {
Set<String> topicTypeNames = new TreeSet<String>();
AssociationField afield = rf.getAssociationField();
Iterator<RoleField> it = afield.getFieldsForRoles().iterator();
while(it.hasNext()) {
RoleField af2 = (RoleField) it.next();
if(!rf.equals(af2)) { // one of the other association fields
Iterator<TopicType> it2 = af2.getDeclaredPlayerTypes().iterator();
while(it2.hasNext()) {
topicTypeNames.add(((TopicType)it2.next()).getName());
}
}
}
return topicTypeNames.toString();
}
private static Component getCardinality(String id, final FieldAssignmentModel fam) {
LoadableDetachableModel<List<Cardinality>> cardinalityChoicesModel = new LoadableDetachableModel<List<Cardinality>>() {
@Override
protected List<Cardinality> load() {
return Cardinality.getCardinalityTypes(fam.getFieldAssignment().getFieldDefinition().getTopicMap());
}
};
final IModel<Cardinality> cardModel = new MutableLoadableDetachableModel<Cardinality>() {
@Override
protected Cardinality load() {
return fam.getFieldAssignment().getCardinality();
}
@Override
public void setObject(Cardinality card) {
fam.getFieldAssignment().getFieldDefinition().setCardinality(card);
super.setObject(card);
}
};
AjaxOntopolyDropDownChoice<Cardinality> choice = new AjaxOntopolyDropDownChoice<Cardinality>(id, cardModel,
cardinalityChoicesModel, new TopicChoiceRenderer<Cardinality>());
return choice;
}
}