001package de.deepamehta.plugins.topicmaps.model; 002 003import de.deepamehta.core.JSONEnabled; 004import de.deepamehta.core.model.TopicModel; 005import de.deepamehta.core.util.DeepaMehtaUtils; 006 007import org.codehaus.jettison.json.JSONObject; 008 009import java.awt.Point; 010 011import java.util.Map; 012import java.util.logging.Logger; 013 014 015 016/** 017 * A topicmap viewmodel: a collection of topics and associations plus their view properties. 018 * <p> 019 * Features: 020 * - Serialization to JSON. 021 */ 022public class TopicmapViewmodel implements JSONEnabled { 023 024 // ---------------------------------------------------------------------------------------------- Instance Variables 025 026 private TopicModel topicmapTopic; 027 private Map<Long, TopicViewmodel> topics; 028 private Map<Long, AssociationViewmodel> assocs; 029 030 private Logger logger = Logger.getLogger(getClass().getName()); 031 032 // ---------------------------------------------------------------------------------------------------- Constructors 033 034 public TopicmapViewmodel(TopicModel topicmapTopic, Map<Long, TopicViewmodel> topics, 035 Map<Long, AssociationViewmodel> assocs) { 036 this.topicmapTopic = topicmapTopic; 037 this.topics = topics; 038 this.assocs = assocs; 039 } 040 041 // -------------------------------------------------------------------------------------------------- Public Methods 042 043 public long getId() { 044 return topicmapTopic.getId(); 045 } 046 047 // --- 048 049 public Iterable<TopicViewmodel> getTopics() { 050 return topics.values(); 051 } 052 053 public Iterable<AssociationViewmodel> getAssociations() { 054 return assocs.values(); 055 } 056 057 // --- 058 059 public TopicViewmodel getTopic(long id) { 060 return topics.get(id); 061 } 062 063 public AssociationViewmodel getAssociation(long id) { 064 return assocs.get(id); 065 } 066 067 // --- 068 069 @Override 070 public JSONObject toJSON() { 071 try { 072 return new JSONObject() 073 .put("info", topicmapTopic.toJSON()) 074 .put("topics", DeepaMehtaUtils.toJSONArray(topics.values())) 075 .put("assocs", DeepaMehtaUtils.toJSONArray(assocs.values())); 076 } catch (Exception e) { 077 throw new RuntimeException("Serialization failed (" + this + ")", e); 078 } 079 } 080 081 @Override 082 public String toString() { 083 return "topicmap " + getId(); 084 } 085 086 // -------------------------------------------------------------------------------------------------- Nested Classes 087 088 // Note: there is a client-side equivalent in canvas_view.js (deepamehta-webclient plugin) 089 public class GridPositioning { 090 091 // Settings 092 private final int GRID_DIST_X = 220; // MAX_TOPIC_LABEL_WIDTH + 20 pixel padding 093 private final int GRID_DIST_Y = 80; 094 private final int START_X; 095 private final int START_Y = 50; 096 private final int MIN_Y = -9999; 097 098 private final int canvasWidth; 099 private final int transX; 100 101 private int gridX; 102 private int gridY; 103 104 // --- Constructors --- 105 106 public GridPositioning(int canvasWidth, int transX) { 107 this.canvasWidth = canvasWidth; 108 this.transX = transX; 109 START_X = 50 - transX; 110 // 111 Point startPos = findStartPostition(); 112 gridX = startPos.x; 113 gridY = startPos.y; 114 } 115 116 // --- Public Methods --- 117 118 public Point nextPosition() { 119 Point pos = new Point(gridX, gridY); 120 advancePosition(); 121 return pos; 122 } 123 124 // --- Private Methods --- 125 126 private Point findStartPostition() { 127 int maxY = MIN_Y; 128 for (TopicViewmodel topic : topics.values()) { 129 if (topic.getY() > maxY) { 130 maxY = topic.getY(); 131 } 132 } 133 int x = START_X; 134 int y = maxY != MIN_Y ? maxY + GRID_DIST_Y : START_Y; 135 return new Point(x, y); 136 } 137 138 private void advancePosition() { 139 if (gridX + GRID_DIST_X + transX > canvasWidth) { 140 gridX = START_X; 141 gridY += GRID_DIST_Y; 142 } else { 143 gridX += GRID_DIST_X; 144 } 145 } 146 } 147}