/*
* #!
* Ontopia Navigator
* #-
* 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 net.ontopia.topicmaps.nav2.portlets.pojos;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.query.core.ParsedQueryIF;
import net.ontopia.topicmaps.utils.TopicStringifiers;
import net.ontopia.utils.OntopiaRuntimeException;
/**
* INTERNAL: This component can produce a model representing a menu
* structure.
*/
public class Menu {
private TopicIF topic;
private TopicIF owner;
public Menu(TopicIF topic) {
try {
this.topic = topic;
TopicMapIF tm = topic.getTopicMap();
ParsedQueryIF ownerQuery = MenuUtils.optimisticParse("select $OWNER from " +
"menu:owned-by(%topic% : menu:owned, $OWNER : menu:owner)?", tm);
owner = (TopicIF)MenuUtils.getFirstValue(topic, ownerQuery);
} catch (Exception e) {
throw new OntopiaRuntimeException(e);
}
}
/**
* The title of this Menu as a String.
*/
public String getTitle() {
return (topic != null ? TopicStringifiers.toString(topic) : null);
}
/**
* Get the topic of this Menu.
*/
public TopicIF getTopic() {
return topic;
}
/**
* Get the owner of this Menu.
*/
public TopicIF getOwner() {
return owner;
}
/**
* Get the children of this Menu.
*/
public List getChildren() {
return buildChildren(topic);
}
/**
* Check if this Menu has children.
*/
public boolean getHasChildren() {
return !getChildren().isEmpty();
}
/**
* Sets the title of this Menu.
*/
public void setTitle(String title) {
MenuUtils.setUniqueTopicName(topic, title);
}
/**
* Set related owner topic.
*/
public void setOwner(TopicIF owner) {
this.owner = owner;
MenuUtils.setUniqueAssociation(topic, "menu:owned", "menu:owned-by",
"menu:owner", owner);
}
/**
* Create new heading as child of this menu
* @return The heading that was created.
*/
public Heading createHeading(String title) {
return MenuUtils.createHeading(topic, title);
}
/**
* Create new item as child of this menu
* @return The item that was created.
*/
public Item createItem(String title) {
return MenuUtils.createItem(topic, title);
}
/**
* Delete this menu with all headings and items
*/
public void delete() {
Collection children = getChildren();
Iterator childrenIt = children.iterator();
while (childrenIt.hasNext()) {
ChildIF currentChild = (ChildIF)childrenIt.next();
currentChild.delete();
}
// Delete the topic, all associations it's part of and all its occurrences
topic.remove();
}
/**
* Build the Heading of a given topic, from the topic map content.
*/
private static Heading buildHeading(TopicIF topic) {
Heading heading = new Heading(topic);
heading.children = buildChildren(topic);
return heading;
}
/**
* Build the Item of a given topic, from the topic map content.
*/
private static Item buildItem(TopicIF topic) {
TopicMapIF tm = topic.getTopicMap();
ParsedQueryIF itemTopicQuery = MenuUtils.optimisticParse(
"select $TOPIC from " +
"menu:item-topic(%topic% : menu:item, $TOPIC : menu:topic)?", tm);
ParsedQueryIF linkQuery = MenuUtils.optimisticParse(
"select $LINK from menu:link(%topic%, $LINK)?", tm);
ParsedQueryIF imageQuery = MenuUtils.optimisticParse(
"select $IMAGE from menu:image(%topic%, $IMAGE)?", tm);
Item item = new Item(topic);
item.associatedTopic = (TopicIF)MenuUtils
.getFirstValue(topic,itemTopicQuery);
item.link = (String)MenuUtils.getFirstValue(topic, linkQuery);
item.image = (String)MenuUtils.getFirstValue(topic, imageQuery);
String query = item.getCondition();
item.condition = (query == null) || MenuUtils
.getResultTrue(item.associatedTopic, query);
return item;
}
/**
* Build the List of children of a given parent, from the topic map content.
*/
private static List buildChildren(TopicIF topic) {
TopicMapIF tm = topic.getTopicMap();
ParsedQueryIF childrenQuery = MenuUtils.optimisticParse(
"select $CHILD, $SORT from " +
"menu:parent-child(%topic% : menu:parent, $CHILD : menu:child), " +
"{ menu:sort($CHILD, $SORT) } order by $SORT?", tm);
ParsedQueryIF headingsQuery = MenuUtils.optimisticParse(
"select $CHILD from " +
"menu:parent-child(%topic% : menu:parent, $CHILD : menu:child), " +
"instance-of($CHILD, menu:heading)?", tm);
List childrenTopics = MenuUtils.getResultValues(topic, childrenQuery);
List headingsTopics = MenuUtils.getResultValues(topic, headingsQuery);
// populate children
List children = new ArrayList(childrenTopics.size());
for (int i=0; i < childrenTopics.size(); i++) {
TopicIF child = (TopicIF)childrenTopics.get(i);
if (headingsTopics.contains(child))
children.add(buildHeading(child));
else
children.add(buildItem(child));
}
return children;
}
// --- MenuObjectIF
public interface MenuObjectIF {
/**
* Get the title as a String.
*/
public String getTitle();
/**
* Get the topic representing this MenuObjectIF as a String.
*/
public TopicIF getTopic();
/**
* Check if this MenuObjectIF has children.
*/
public boolean getHasChildren();
/**
* Sets the title.
*/
public void setTitle(String title);
/**
* Delete this child.
*/
public void delete();
}
// --- ParentIF
public interface ParentIF extends MenuObjectIF {
/**
* Get the children.
*/
public List getChildren();
/**
* Create new heading as child of this menu
* @return The heading that was created.
*/
public Heading createHeading(String title);
/**
* Create new item as child of this menu
* @return The item that was created.
*/
public Item createItem(String title);
}
// --- ChildIF
public interface ChildIF extends MenuObjectIF {
/**
* Check whether this is a Heading.
*/
public boolean getIsHeading();
/**
* Check whether this is an Item.
*/
public boolean getIsItem();
/**
* Moves this child one step higher up the list of children on its parent.
* has no effect if it is already first.
*/
public void moveOneUp();
/**
* Moves this child one step further down its parent's list of children.
* Has no effect if it is already last.
*/
public void moveOneDown();
}
// --- Heading
public static class Heading implements ChildIF, ParentIF {
private TopicIF topic;
protected List children;
public Heading(TopicIF topic) {
this.topic = topic;
}
/**
* Check whether this is a Heading.
* @return true, since it is a Heading.
*/
public boolean getIsHeading() {
return true;
}
/**
* Check whether this is an Item.
* @return false, since it is not an Item.
*/
public boolean getIsItem() {
return false;
}
/**
* The title of this Heading as a String.
*/
public String getTitle() {
return (topic != null ? TopicStringifiers.toString(topic) : null);
}
/**
* Get the topic of this Heading.
*/
public TopicIF getTopic() {
return topic;
}
/**
* Get the children of this Heading.
*/
public List getChildren() {
return buildChildren(topic);
}
/**
* Check if this Heading has children.
*/
public boolean getHasChildren() {
return !children.isEmpty();
}
/**
* Sets the title of this Heading.
*/
public void setTitle(String title) {
MenuUtils.setUniqueTopicName(topic, title);
}
/**
* Moves this Heading one step up the list of children on its parent.
* has no effect if it is already first
*/
public void moveOneUp() {
MenuUtils.moveOne(topic, MenuUtils.UP);
}
/**
* Moves this Heading one step down the list of children on its parent.
* Has no effect if it is already last.
*/
public void moveOneDown() {
MenuUtils.moveOne(topic, MenuUtils.DOWN);
}
/**
* Create new Heading as child of this Heading
* @return The heading that was created.
*/
public Heading createHeading(String title) {
return MenuUtils.createHeading(topic, title);
}
/**
* Create new Item as child of this Heading.
* @return The item that was created.
*/
public Item createItem(String title) {
return MenuUtils.createItem(topic, title);
}
/**
* Delete this Heading with all its descendants.
*/
public void delete() {
// Delete all children.
Collection children = getChildren();
Iterator childrenIt = children.iterator();
while (childrenIt.hasNext()) {
ChildIF currentChild = (ChildIF)childrenIt.next();
currentChild.delete();
}
// Delete the topic, all associations it's part of and all its occurrences
topic.remove();
}
}
// --- Item
public static class Item implements ChildIF {
protected TopicIF associatedTopic;
protected String link;
protected String image;
protected String conditionString;
protected boolean condition;
private TopicIF topic;
/**
* Create a new Item, represented by the given topic.
*/
public Item(TopicIF topic) {
this.topic = topic;
}
/**
* Check whether this Item is a Heading.
* @return false, since it is not a Heading.
*/
public boolean getIsHeading() {
return false;
}
/**
* Check whether this is an Item.
* @return true, since it is an Item.
*/
public boolean getIsItem() {
return true;
}
/**
* Get the title of this Item as a String.
*/
public String getTitle() {
return (topic != null ? TopicStringifiers.toString(topic) : null);
}
/**
* Get the associated topic of this Item.
*/
public TopicIF getAssociatedTopic() {
return associatedTopic;
}
/**
* Get the topic of this Item.
*/
public TopicIF getTopic() {
return topic;
}
/**
* The link occurrence as a String.
*/
public String getLink() {
return link;
}
/**
* Get the image occurrence as a String.
*/
public String getImage() {
return image;
}
/**
* Check if this Item has children.
* $return false, since an Item cannot have any children.
*/
public boolean getHasChildren() {
return false;
}
/**
* Check the condition of this Item.
*/
public boolean getConditionTrue() {
return condition;
}
/**
* Sets the title of the Item topic.
*/
public void setTitle(String title) {
MenuUtils.setUniqueTopicName(topic, title);
}
/**
* Set the associated topic.
*/
public void setAssociatedTopic(TopicIF topic) {
this.associatedTopic = topic;
MenuUtils.setUniqueAssociation(this.topic, "menu:item", "menu:item-topic",
"menu:topic", associatedTopic);
updateConditionState();
}
/**
* Set the link occurrence value.
*/
public void setLink(String link) {
MenuUtils.setUniqueOccurrence(topic, "menu:link", link);
this.link = link;
}
/**
* Set the image occurrence value.
*/
public void setImage(String image) {
MenuUtils.setUniqueOccurrence(topic, "menu:image", image);
this.image = image;
}
/**
* Get the condition occurrence value as a String.
*/
public String getCondition() {
TopicMapIF tm = topic.getTopicMap();
ParsedQueryIF conditionQuery = MenuUtils.optimisticParse(
"select $CONDITION from menu:condition(%topic%, $CONDITION)?", tm);
return (String)MenuUtils.getFirstValue(topic, conditionQuery);
}
/**
* Set the condition occurrence value.
*/
public void setCondition(String condition) {
MenuUtils.setUniqueOccurrence(topic, "menu:condition", condition);
conditionString = condition;
updateConditionState();
}
/**
* Moves this item one step higher up the list of children on its parent.
* has no effect if it is already first.
*/
public void moveOneUp() {
MenuUtils.moveOne(topic, MenuUtils.UP);
}
/**
* Moves this item one step further down the list of children on its parent.
* Has no effect if it is already last.
*/
public void moveOneDown() {
MenuUtils.moveOne(topic, MenuUtils.DOWN);
}
/**
* Delete this Item.
*/
public void delete() {
// Delete the topic, all associations it's part of and all its occurrences
topic.remove();
}
/**
* Update the state of the boolean condition value on this item.
* This method should be called whenver a new associated topic is set or
* the conditionString has been changed, either of which may change the
* condition state.
*/
private void updateConditionState() {
condition = conditionString == null || (associatedTopic != null &&
MenuUtils.getResultTrue(associatedTopic, conditionString));
}
}
}