2 * model of lands for JTree view
\r
4 * Copyright(c) 2008 olyutorskii
\r
5 * $Id: LandsModel.java 953 2009-12-06 16:42:14Z olyutorskii $
\r
8 package jp.sourceforge.jindolf;
\r
10 import java.io.IOException;
\r
11 import java.net.URISyntaxException;
\r
12 import java.util.Collections;
\r
13 import java.util.HashMap;
\r
14 import java.util.LinkedList;
\r
15 import java.util.List;
\r
16 import java.util.Map;
\r
17 import javax.swing.event.EventListenerList;
\r
18 import javax.swing.event.TreeModelEvent;
\r
19 import javax.swing.event.TreeModelListener;
\r
20 import javax.swing.tree.TreeModel;
\r
21 import javax.swing.tree.TreePath;
\r
22 import javax.xml.parsers.DocumentBuilder;
\r
23 import javax.xml.parsers.ParserConfigurationException;
\r
24 import jp.sourceforge.jindolf.corelib.LandDef;
\r
25 import org.xml.sax.SAXException;
\r
28 * 国の集合。あらゆるデータモデルの大元。
\r
32 public class LandsModel implements TreeModel{ // ComboBoxModelも付けるか?
\r
35 * 村IDで範囲指定した、村のセクション集合。国-村間の中間ツリー。
\r
36 * @see javax.swing.tree.TreeModel
\r
38 private static final class VillageSection{
\r
41 * 与えられた国の全ての村を、指定されたinterval間隔でセクション化する。
\r
43 * @param interval セクションの間隔
\r
45 * @throws java.lang.IllegalArgumentException intervalが正でない
\r
47 private static List<VillageSection> getSectionList(Land land,
\r
49 throws IllegalArgumentException{
\r
51 throw new IllegalArgumentException();
\r
54 List<Village> villageList = land.getVillageList();
\r
55 Village village1st = villageList.get(0);
\r
56 Village villageLast = villageList.get(villageList.size() - 1);
\r
58 int startID = village1st.getVillageIDNum();
\r
59 int endID = villageLast.getVillageIDNum();
\r
61 List<VillageSection> result = new LinkedList<VillageSection>();
\r
63 int fixedStart = startID / interval * interval;
\r
64 for(int ct = fixedStart; ct <= endID; ct += interval){
\r
65 VillageSection section =
\r
66 new VillageSection(land, ct, ct + interval - 1);
\r
67 result.add(section);
\r
70 return Collections.unmodifiableList(result);
\r
73 private final int startID;
\r
74 private final int endID;
\r
75 private final String prefix;
\r
77 private final List<Village> villageList = new LinkedList<Village>();
\r
82 * @param startID 開始村ID
\r
83 * @param endID 終了村ID
\r
84 * @throws java.lang.IndexOutOfBoundsException IDの範囲指定が変
\r
86 private VillageSection(Land land, int startID, int endID)
\r
87 throws IndexOutOfBoundsException{
\r
90 if(startID < 0 || startID > endID){
\r
91 throw new IndexOutOfBoundsException();
\r
94 this.startID = startID;
\r
96 this.prefix = land.getLandDef().getLandPrefix();
\r
98 for(Village village : land.getVillageList()){
\r
99 int id = village.getVillageIDNum();
\r
100 if(startID <= id && id <= endID){
\r
101 this.villageList.add(village);
\r
109 * セクションに含まれる村の総数を返す。
\r
112 private int getVillageCount(){
\r
113 return this.villageList.size();
\r
117 * セクションに含まれるindex番目の村を返す。
\r
118 * @param index インデックス
\r
119 * @return index番目の村
\r
121 private Village getVillage(int index){
\r
122 return this.villageList.get(index);
\r
126 * セクションにおける、指定された子(村)のインデックス位置を返す。
\r
130 private int getIndexOfVillage(Object child){
\r
131 return this.villageList.indexOf(child);
\r
140 public String toString(){
\r
141 StringBuilder result = new StringBuilder();
\r
142 result.append(this.prefix).append(this.startID);
\r
143 result.append(" ~ ");
\r
144 result.append(this.prefix).append(this.endID);
\r
145 return result.toString();
\r
149 private static final String ROOT = "ROOT";
\r
150 private static final int SECTION_INTERVAL = 100;
\r
152 private final List<Land> landList = new LinkedList<Land>();
\r
153 private final List<Land> unmodList =
\r
154 Collections.unmodifiableList(this.landList);
\r
155 private final Map<Land, List<VillageSection>> sectionMap =
\r
156 new HashMap<Land, List<VillageSection>>();
\r
157 private boolean isLandListLoaded = false;
\r
159 private final EventListenerList listeners = new EventListenerList();
\r
161 private boolean ascending = false;
\r
165 * この時点ではまだ国一覧が読み込まれない。
\r
167 public LandsModel(){
\r
175 * @throws java.io.IOException ネットワーク入出力の異常
\r
177 public void loadVillageList(Land land) throws IOException{
\r
178 land.updateVillageList();
\r
180 List<VillageSection> sectionList =
\r
181 VillageSection.getSectionList(land, SECTION_INTERVAL);
\r
182 this.sectionMap.put(land, sectionList);
\r
184 int[] childIndices = new int[sectionList.size()];
\r
185 for(int ct = 0; ct < childIndices.length; ct++){
\r
186 childIndices[ct] = ct;
\r
188 Object[] children = sectionList.toArray();
\r
190 Object[] path = {ROOT, land};
\r
191 TreePath treePath = new TreePath(path);
\r
192 TreeModelEvent event = new TreeModelEvent(this,
\r
196 fireTreeStructureChanged(event);
\r
204 // TODO static にできない?
\r
205 public void loadLandList(){
\r
206 if(this.isLandListLoaded) return;
\r
208 this.landList.clear();
\r
210 List<LandDef> landDefList;
\r
212 DocumentBuilder builder = XmlUtils.createDocumentBuilder();
\r
213 landDefList = LandDef.buildLandDefList(builder);
\r
214 }catch(IOException e){
\r
215 Jindolf.logger().fatal("failed to load land list", e);
\r
217 }catch(SAXException e){
\r
218 Jindolf.logger().fatal("failed to load land list", e);
\r
220 }catch(URISyntaxException e){
\r
221 Jindolf.logger().fatal("failed to load land list", e);
\r
223 }catch(ParserConfigurationException e){
\r
224 Jindolf.logger().fatal("failed to load land list", e);
\r
228 for(LandDef landDef : landDefList){
\r
229 Land land = new Land(landDef);
\r
230 this.landList.add(land);
\r
233 this.isLandListLoaded = true;
\r
235 fireLandListChanged();
\r
241 * ツリー内容が更新された事をリスナーに通知する。
\r
243 private void fireLandListChanged(){
\r
244 int size = this.landList.size();
\r
245 int[] childIndices = new int[size];
\r
246 for(int ct = 0; ct < size; ct++){
\r
248 childIndices[ct] = index;
\r
251 Object[] children = this.landList.toArray();
\r
253 TreePath treePath = new TreePath(ROOT);
\r
254 TreeModelEvent event = new TreeModelEvent(this,
\r
258 fireTreeStructureChanged(event);
\r
265 * 場合によってはTreeModelEventが発生する。
\r
266 * @param ascending trueなら昇順
\r
268 public void setAscending(boolean ascending){
\r
269 if(this.ascending == ascending) return;
\r
271 this.ascending = ascending;
\r
272 fireLandListChanged();
\r
279 * @param l {@inheritDoc}
\r
281 public void addTreeModelListener(TreeModelListener l){
\r
282 this.listeners.add(TreeModelListener.class, l);
\r
288 * @param l {@inheritDoc}
\r
290 public void removeTreeModelListener(TreeModelListener l){
\r
291 this.listeners.remove(TreeModelListener.class, l);
\r
299 private TreeModelListener[] getTreeModelListeners(){
\r
300 return this.listeners.getListeners(TreeModelListener.class);
\r
305 * @param event ツリーイベント
\r
307 protected void fireTreeStructureChanged(TreeModelEvent event){
\r
308 for(TreeModelListener listener : getTreeModelListeners()){
\r
309 listener.treeStructureChanged(event);
\r
318 public List<Land> getLandList(){
\r
319 return this.unmodList;
\r
324 * @param parent {@inheritDoc}
\r
325 * @param index {@inheritDoc}
\r
326 * @return {@inheritDoc}
\r
328 public Object getChild(Object parent, int index){
\r
329 if(index < 0) return null;
\r
330 if(index >= getChildCount(parent)) return null;
\r
332 if(parent == ROOT){
\r
333 List<Land> list = getLandList();
\r
334 int landIndex = index;
\r
335 if( ! this.ascending) landIndex = list.size() - index - 1;
\r
336 Land land = list.get(landIndex);
\r
339 if(parent instanceof Land){
\r
340 Land land = (Land)parent;
\r
341 List<VillageSection> sectionList = this.sectionMap.get(land);
\r
342 int sectIndex = index;
\r
343 if( ! this.ascending) sectIndex = sectionList.size() - index - 1;
\r
344 VillageSection section = sectionList.get(sectIndex);
\r
347 if(parent instanceof VillageSection){
\r
348 VillageSection section = (VillageSection)parent;
\r
349 int vilIndex = index;
\r
350 if( ! this.ascending){
\r
351 vilIndex = section.getVillageCount() - index - 1;
\r
353 Village village = section.getVillage(vilIndex);
\r
361 * @param parent {@inheritDoc}
\r
362 * @return {@inheritDoc}
\r
364 public int getChildCount(Object parent){
\r
365 if(parent == ROOT){
\r
366 return getLandList().size();
\r
368 if(parent instanceof Land){
\r
369 Land land = (Land)parent;
\r
370 List<VillageSection> sectionList = this.sectionMap.get(land);
\r
371 if(sectionList == null) return 0;
\r
372 return sectionList.size();
\r
374 if(parent instanceof VillageSection){
\r
375 VillageSection section = (VillageSection)parent;
\r
376 return section.getVillageCount();
\r
383 * @param parent {@inheritDoc}
\r
384 * @param child {@inheritDoc}
\r
385 * @return {@inheritDoc}
\r
387 public int getIndexOfChild(Object parent, Object child){
\r
388 if(child == null) return -1;
\r
389 if(parent == ROOT){
\r
390 List<Land> list = getLandList();
\r
391 int index = list.indexOf(child);
\r
392 if( ! this.ascending) index = list.size() - index - 1;
\r
395 if(parent instanceof Land){
\r
396 Land land = (Land)parent;
\r
397 List<VillageSection> sectionList = this.sectionMap.get(land);
\r
398 int index = sectionList.indexOf(child);
\r
399 if( ! this.ascending) index = sectionList.size() - index - 1;
\r
402 if(parent instanceof VillageSection){
\r
403 VillageSection section = (VillageSection)parent;
\r
404 int index = section.getIndexOfVillage(child);
\r
405 if( ! this.ascending){
\r
406 index = section.getVillageCount() - index - 1;
\r
415 * @return {@inheritDoc}
\r
417 public Object getRoot(){
\r
423 * @param node {@inheritDoc}
\r
424 * @return {@inheritDoc}
\r
426 public boolean isLeaf(Object node){
\r
427 if(node == ROOT) return false;
\r
428 if(node instanceof Land) return false;
\r
429 if(node instanceof VillageSection) return false;
\r
430 if(node instanceof Village) return true;
\r
436 * ※ たぶん使わないので必ず失敗させている。
\r
437 * @param path {@inheritDoc}
\r
438 * @param newValue {@inheritDoc}
\r
440 public void valueForPathChanged(TreePath path, Object newValue){
\r
441 throw new UnsupportedOperationException("Not supported yet.");
\r