2 * model of lands for JTree view
4 * License : The MIT License
5 * Copyright(c) 2008 olyutorskii
8 package jp.sfjp.jindolf.data;
10 import java.io.IOException;
11 import java.net.URISyntaxException;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.LinkedList;
15 import java.util.List;
17 import java.util.logging.Level;
18 import java.util.logging.Logger;
19 import javax.swing.event.EventListenerList;
20 import javax.swing.event.TreeModelEvent;
21 import javax.swing.event.TreeModelListener;
22 import javax.swing.tree.TreeModel;
23 import javax.swing.tree.TreePath;
24 import javax.xml.parsers.DocumentBuilder;
25 import javax.xml.parsers.ParserConfigurationException;
26 import jp.sfjp.jindolf.dxchg.XmlUtils;
27 import jp.sourceforge.jindolf.corelib.LandDef;
28 import org.xml.sax.SAXException;
35 public class LandsModel implements TreeModel{ // ComboBoxModelも付けるか?
37 private static final String ROOT = "ROOT";
38 private static final int SECTION_INTERVAL = 100;
40 private static final Logger LOGGER = Logger.getAnonymousLogger();
43 private final List<Land> landList = new LinkedList<>();
44 private final List<Land> unmodList =
45 Collections.unmodifiableList(this.landList);
46 private final Map<Land, List<VillageSection>> sectionMap =
48 private boolean isLandListLoaded = false;
50 private final EventListenerList listeners = new EventListenerList();
52 private boolean ascending = false;
56 * この時点ではまだ国一覧が読み込まれない。
64 * 指定した国の村一覧を更新しイベントを投げる。
67 public void updateVillageList(Land land){
68 List<VillageSection> sectionList =
69 VillageSection.getSectionList(land, SECTION_INTERVAL);
70 this.sectionMap.put(land, sectionList);
72 int[] childIndices = new int[sectionList.size()];
73 for(int ct = 0; ct < childIndices.length; ct++){
74 childIndices[ct] = ct;
76 Object[] children = sectionList.toArray();
78 Object[] path = {ROOT, land};
79 TreePath treePath = new TreePath(path);
80 TreeModelEvent event = new TreeModelEvent(this,
84 fireTreeStructureChanged(event);
93 public void loadLandList(){
94 if(this.isLandListLoaded) return;
96 this.landList.clear();
98 List<LandDef> landDefList;
100 DocumentBuilder builder = XmlUtils.createDocumentBuilder();
101 landDefList = LandDef.buildLandDefList(builder);
105 | ParserConfigurationException
107 LOGGER.log(Level.SEVERE, "failed to load land list", e);
111 for(LandDef landDef : landDefList){
112 Land land = new Land(landDef);
113 this.landList.add(land);
116 this.isLandListLoaded = true;
118 fireLandListChanged();
124 * ツリー内容が更新された事をリスナーに通知する。
126 private void fireLandListChanged(){
127 int size = this.landList.size();
128 int[] childIndices = new int[size];
129 for(int ct = 0; ct < size; ct++){
131 childIndices[ct] = index;
134 Object[] children = this.landList.toArray();
136 TreePath treePath = new TreePath(ROOT);
137 TreeModelEvent event = new TreeModelEvent(this,
141 fireTreeStructureChanged(event);
148 * 場合によってはTreeModelEventが発生する。
149 * @param ascending trueなら昇順
151 public void setAscending(boolean ascending){
152 if(this.ascending == ascending) return;
154 this.ascending = ascending;
155 fireLandListChanged();
162 * @param l {@inheritDoc}
165 public void addTreeModelListener(TreeModelListener l){
166 this.listeners.add(TreeModelListener.class, l);
172 * @param l {@inheritDoc}
175 public void removeTreeModelListener(TreeModelListener l){
176 this.listeners.remove(TreeModelListener.class, l);
184 private TreeModelListener[] getTreeModelListeners(){
185 return this.listeners.getListeners(TreeModelListener.class);
190 * @param event ツリーイベント
192 protected void fireTreeStructureChanged(TreeModelEvent event){
193 for(TreeModelListener listener : getTreeModelListeners()){
194 listener.treeStructureChanged(event);
203 public List<Land> getLandList(){
204 return this.unmodList;
209 * @param parent {@inheritDoc}
210 * @param index {@inheritDoc}
211 * @return {@inheritDoc}
214 public Object getChild(Object parent, int index){
215 if(index < 0) return null;
216 if(index >= getChildCount(parent)) return null;
219 List<Land> list = getLandList();
220 int landIndex = index;
221 if( ! this.ascending) landIndex = list.size() - index - 1;
222 Land land = list.get(landIndex);
225 if(parent instanceof Land){
226 Land land = (Land) parent;
227 List<VillageSection> sectionList = this.sectionMap.get(land);
228 int sectIndex = index;
229 if( ! this.ascending) sectIndex = sectionList.size() - index - 1;
230 VillageSection section = sectionList.get(sectIndex);
233 if(parent instanceof VillageSection){
234 VillageSection section = (VillageSection) parent;
235 int vilIndex = index;
236 if( ! this.ascending){
237 vilIndex = section.getVillageCount() - index - 1;
239 Village village = section.getVillage(vilIndex);
247 * @param parent {@inheritDoc}
248 * @return {@inheritDoc}
251 public int getChildCount(Object parent){
253 return getLandList().size();
255 if(parent instanceof Land){
256 Land land = (Land) parent;
257 List<VillageSection> sectionList = this.sectionMap.get(land);
258 if(sectionList == null) return 0;
259 return sectionList.size();
261 if(parent instanceof VillageSection){
262 VillageSection section = (VillageSection) parent;
263 return section.getVillageCount();
270 * @param parent {@inheritDoc}
271 * @param child {@inheritDoc}
272 * @return {@inheritDoc}
275 public int getIndexOfChild(Object parent, Object child){
276 if(child == null) return -1;
278 List<Land> list = getLandList();
279 int index = list.indexOf(child);
280 if( ! this.ascending) index = list.size() - index - 1;
283 if(parent instanceof Land){
284 Land land = (Land) parent;
285 List<VillageSection> sectionList = this.sectionMap.get(land);
286 int index = sectionList.indexOf(child);
287 if( ! this.ascending) index = sectionList.size() - index - 1;
290 if(parent instanceof VillageSection){
291 VillageSection section = (VillageSection) parent;
292 int index = section.getIndexOfVillage(child);
293 if( ! this.ascending){
294 index = section.getVillageCount() - index - 1;
303 * @return {@inheritDoc}
306 public Object getRoot(){
312 * @param node {@inheritDoc}
313 * @return {@inheritDoc}
316 public boolean isLeaf(Object node){
317 if(node == ROOT) return false;
318 if(node instanceof Land) return false;
319 if(node instanceof VillageSection) return false;
320 if(node instanceof Village) return true;
326 * ※ たぶん使わないので必ず失敗させている。
327 * @param path {@inheritDoc}
328 * @param newValue {@inheritDoc}
331 public void valueForPathChanged(TreePath path, Object newValue){
332 throw new UnsupportedOperationException("Not supported yet.");
336 * 村IDで範囲指定した、村のセクション集合。国-村間の中間ツリー。
337 * @see javax.swing.tree.TreeModel
339 private static final class VillageSection{
341 private final int startID;
342 private final int endID;
343 private final String prefix;
345 private final List<Village> villageList = new LinkedList<>();
351 * @param startID 開始村ID
353 * @throws java.lang.IndexOutOfBoundsException IDの範囲指定が変
355 private VillageSection(Land land, int startID, int endID)
356 throws IndexOutOfBoundsException{
359 if(startID < 0 || startID > endID){
360 throw new IndexOutOfBoundsException();
363 this.startID = startID;
365 this.prefix = land.getLandDef().getLandPrefix();
367 for(Village village : land.getVillageList()){
368 int id = village.getVillageIDNum();
369 if(startID <= id && id <= endID){
370 this.villageList.add(village);
379 * 与えられた国の全ての村を、指定されたinterval間隔でセクション化する。
381 * @param interval セクションの間隔
383 * @throws java.lang.IllegalArgumentException intervalが正でない
385 private static List<VillageSection> getSectionList(Land land,
387 throws IllegalArgumentException{
389 throw new IllegalArgumentException();
392 List<Village> villageList = land.getVillageList();
393 Village village1st = villageList.get(0);
394 Village villageLast = villageList.get(villageList.size() - 1);
396 int startID = village1st.getVillageIDNum();
397 int endID = villageLast.getVillageIDNum();
399 List<VillageSection> result = new LinkedList<>();
401 int fixedStart = startID / interval * interval;
402 for(int ct = fixedStart; ct <= endID; ct += interval){
403 VillageSection section =
404 new VillageSection(land, ct, ct + interval - 1);
408 return Collections.unmodifiableList(result);
415 private int getVillageCount(){
416 return this.villageList.size();
420 * セクションに含まれるindex番目の村を返す。
421 * @param index インデックス
424 private Village getVillage(int index){
425 return this.villageList.get(index);
429 * セクションにおける、指定された子(村)のインデックス位置を返す。
433 private int getIndexOfVillage(Object child){
434 return this.villageList.indexOf(child);
443 public String toString(){
444 StringBuilder result = new StringBuilder();
445 result.append(this.prefix).append(this.startID);
446 result.append(" ~ ");
447 result.append(this.prefix).append(this.endID);
448 return result.toString();