テキストの各行をキーと値に分離し、複数テキストファイルを読み込み、キーを突き合わせ照合し、その結果を表示するGUIユーテリティです。
リビジョン | 7079a574a68f75b36c91bbea6de9b868a827f58e (tree) |
---|---|
日時 | 2011-10-19 18:30:04 |
作者 | osabe_masashi <osabe_masashi@MKI9...> |
コミッター | osabe_masashi |
表示モードのバインド対応仕掛中
@@ -9,6 +9,7 @@ import java.util.AbstractSet; | ||
9 | 9 | import java.util.Iterator; |
10 | 10 | import java.util.Map; |
11 | 11 | import java.util.Map.Entry; |
12 | +import java.util.NoSuchElementException; | |
12 | 13 | import java.util.Set; |
13 | 14 | |
14 | 15 | /** |
@@ -19,15 +20,20 @@ public class FilteredRowMap extends AbstractMap<RowKey, RowValues> { | ||
19 | 20 | |
20 | 21 | private Map<RowKey, RowValues> dataMap; |
21 | 22 | |
22 | - private RowFilter rowFilter = DisplayMode.ALL; | |
23 | + private RowFilter rowFilter; | |
23 | 24 | |
24 | 25 | public FilteredRowMap(Map<RowKey, RowValues> dataMap) { |
25 | - if (dataMap == null) { | |
26 | + this(dataMap, DisplayMode.ALL); | |
27 | + } | |
28 | + | |
29 | + public FilteredRowMap(Map<RowKey, RowValues> dataMap, RowFilter rowFilter) { | |
30 | + if (dataMap == null || rowFilter == null) { | |
26 | 31 | throw new IllegalArgumentException(); |
27 | 32 | } |
28 | 33 | this.dataMap = dataMap; |
34 | + this.rowFilter = rowFilter; | |
29 | 35 | } |
30 | - | |
36 | + | |
31 | 37 | public void setRowFilter(RowFilter rowFilter) { |
32 | 38 | if (rowFilter == null) { |
33 | 39 | throw new IllegalArgumentException(); |
@@ -39,9 +45,74 @@ public class FilteredRowMap extends AbstractMap<RowKey, RowValues> { | ||
39 | 45 | return rowFilter; |
40 | 46 | } |
41 | 47 | |
48 | + private static int ref = 0; | |
42 | 49 | |
43 | 50 | @Override |
44 | 51 | public Set<Entry<RowKey, RowValues>> entrySet() { |
45 | - return dataMap.entrySet(); | |
52 | + final Set<Entry<RowKey, RowValues>> set = dataMap.entrySet(); | |
53 | + final RowFilter filter = this.rowFilter; | |
54 | + return new AbstractSet<Entry<RowKey, RowValues>>() { | |
55 | + @Override | |
56 | + public Iterator<Entry<RowKey, RowValues>> iterator() { | |
57 | + ref++; | |
58 | + final Iterator<Entry<RowKey, RowValues>> ite = set.iterator(); | |
59 | + return new Iterator<Entry<RowKey, RowValues>>() { | |
60 | + | |
61 | + private Entry<RowKey, RowValues> nextEntry; | |
62 | + | |
63 | + private void fetch() { | |
64 | + nextEntry = null; | |
65 | + while (ite.hasNext()) { | |
66 | + Entry<RowKey, RowValues> entry = ite.next(); | |
67 | + if (filter.isAcceptable(entry.getValue())) { | |
68 | + nextEntry = entry; | |
69 | + return; | |
70 | + } | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + public boolean hasNext() { | |
76 | + if (nextEntry == null) { | |
77 | + fetch(); | |
78 | + } | |
79 | + return nextEntry != null; | |
80 | + } | |
81 | + | |
82 | + @Override | |
83 | + public Entry<RowKey, RowValues> next() { | |
84 | + if (nextEntry == null) { | |
85 | + fetch(); | |
86 | + } | |
87 | + if (nextEntry == null) { | |
88 | + throw new NoSuchElementException(); | |
89 | + } | |
90 | + Entry<RowKey, RowValues> entry = nextEntry; | |
91 | + this.nextEntry = null; | |
92 | + return entry; | |
93 | + } | |
94 | + | |
95 | + @Override | |
96 | + public void remove() { | |
97 | + throw new UnsupportedOperationException("Not supported yet."); | |
98 | + } | |
99 | + }; | |
100 | + } | |
101 | + | |
102 | + @Override | |
103 | + public int size() { | |
104 | + int cnt = 0; | |
105 | + Iterator<Entry<RowKey, RowValues>> ite = iterator(); | |
106 | + while (ite.hasNext()) { | |
107 | + ite.next(); | |
108 | + cnt++; | |
109 | + } | |
110 | + return cnt; | |
111 | + } | |
112 | + }; | |
113 | + } | |
114 | + | |
115 | + public static int getRef() { | |
116 | + return ref; | |
46 | 117 | } |
47 | 118 | } |
@@ -15,7 +15,7 @@ | ||
15 | 15 | </DimensionLayout> |
16 | 16 | <DimensionLayout dim="1"> |
17 | 17 | <Group type="103" groupAlignment="0" attributes="0"> |
18 | - <Component id="dataViewTableSP" alignment="0" pref="391" max="32767" attributes="0"/> | |
18 | + <Component id="dataViewTableSP" alignment="0" pref="392" max="32767" attributes="0"/> | |
19 | 19 | </Group> |
20 | 20 | </DimensionLayout> |
21 | 21 | </Layout> |
@@ -296,7 +296,7 @@ | ||
296 | 296 | <DimensionLayout dim="0"> |
297 | 297 | <Group type="103" groupAlignment="0" attributes="0"> |
298 | 298 | <Group type="102" alignment="1" attributes="0"> |
299 | - <Component id="statusMessageLabel" pref="225" max="32767" attributes="0"/> | |
299 | + <Component id="statusMessageLabel" pref="235" max="32767" attributes="0"/> | |
300 | 300 | <EmptySpace max="-2" attributes="0"/> |
301 | 301 | <Component id="progressBar" min="-2" max="-2" attributes="0"/> |
302 | 302 | <EmptySpace max="-2" attributes="0"/> |
@@ -38,6 +38,7 @@ import javax.swing.KeyStroke; | ||
38 | 38 | import javax.swing.table.DefaultTableCellRenderer; |
39 | 39 | import org.jdesktop.application.Application; |
40 | 40 | import textkeymatcher.TextKeyMatcherApp; |
41 | +import textkeymatcher.entity.FilteredRowMap; | |
41 | 42 | import textkeymatcher.io.DocArchive; |
42 | 43 | import textkeymatcher.io.FileDocArchive; |
43 | 44 | import textkeymatcher.service.LineDataBuilder; |
@@ -602,6 +603,7 @@ public class TextKeyMatcherView extends FrameView implements ExitListener { | ||
602 | 603 | */ |
603 | 604 | @Override |
604 | 605 | public void willExit(EventObject event) { |
606 | + logger.log(Level.INFO, "ref={0}", new Object[] {FilteredRowMap.getRef()}); | |
605 | 607 | logger.log(Level.INFO, "willExit"); |
606 | 608 | } |
607 | 609 |
@@ -7,10 +7,15 @@ package textkeymatcher.ui.model; | ||
7 | 7 | import java.beans.PropertyChangeListener; |
8 | 8 | import java.beans.PropertyChangeSupport; |
9 | 9 | import java.io.IOException; |
10 | +import java.util.Map; | |
10 | 11 | import org.apache.commons.lang3.StringUtils; |
12 | +import textkeymatcher.entity.DisplayMode; | |
13 | +import textkeymatcher.entity.FilteredRowMap; | |
11 | 14 | import textkeymatcher.entity.KeyMatchedRowMap; |
12 | 15 | import textkeymatcher.entity.KeyMatchedRowView; |
13 | 16 | import textkeymatcher.entity.LineDataList; |
17 | +import textkeymatcher.entity.RowKey; | |
18 | +import textkeymatcher.entity.RowValues; | |
14 | 19 | import textkeymatcher.io.DocArchive; |
15 | 20 | import textkeymatcher.io.TextKeyMatcherDoc; |
16 | 21 | import textkeymatcher.entity.KeyMatcher; |
@@ -27,17 +32,37 @@ public class DataViewTableModel extends KeyMatchedRowView implements TextKeyMatc | ||
27 | 32 | private PropertyChangeSupport propCng = new PropertyChangeSupport(this); |
28 | 33 | |
29 | 34 | /** |
35 | + * キーカラムのカラム名. | |
36 | + */ | |
37 | + public static final String COLUMN_NAME_KEY = "key"; | |
38 | + | |
39 | + /** | |
30 | 40 | * キーマッチング方法のプロパティ名 |
31 | 41 | */ |
32 | 42 | public static final String PROPERTY_KEY_MATCHER = "keyMatcher"; |
33 | 43 | |
34 | 44 | /** |
45 | + * 表示モード(行フィルタ方法)のプロパティ名 | |
46 | + */ | |
47 | + public static final String PROPERTY_DISPLAY_MODE = "displayMode"; | |
48 | + | |
49 | + /** | |
50 | + * データ変更フラグ.<br> | |
51 | + */ | |
52 | + public static final String PROPERTY_DIRTY = "dirty"; | |
53 | + | |
54 | + /** | |
35 | 55 | * 取り込んだデータソースや、キーマッチングなどを決定している |
36 | 56 | * データマップ |
37 | 57 | */ |
38 | 58 | private KeyMatchedRowMap rowMap = new KeyMatchedRowMap(); |
39 | 59 | |
40 | 60 | /** |
61 | + * データマップのカラムの関係により行の表示有無を切り替える. | |
62 | + */ | |
63 | + private DisplayMode displayMode = DisplayMode.ALL; | |
64 | + | |
65 | + /** | |
41 | 66 | * ダーティフラグ.<br> |
42 | 67 | * データソースが追加・クリアされるか、キーマッチャが変更されると設定される.<br> |
43 | 68 | * 一度設定されると、明示にクリアされるまで維持される.<br> |
@@ -86,7 +111,7 @@ public class DataViewTableModel extends KeyMatchedRowView implements TextKeyMatc | ||
86 | 111 | public void setDirty(boolean dirty) { |
87 | 112 | boolean oldValue = this.dirty; |
88 | 113 | this.dirty = dirty; |
89 | - propCng.firePropertyChange("dirty", oldValue, dirty); | |
114 | + propCng.firePropertyChange(PROPERTY_DIRTY, oldValue, dirty); | |
90 | 115 | } |
91 | 116 | |
92 | 117 |
@@ -164,7 +189,7 @@ public class DataViewTableModel extends KeyMatchedRowView implements TextKeyMatc | ||
164 | 189 | @Override |
165 | 190 | public String getColumnName(int i) { |
166 | 191 | if (i == 0) { |
167 | - return "Key"; | |
192 | + return COLUMN_NAME_KEY; | |
168 | 193 | } |
169 | 194 | int column = i - 1; // 左端はキーカラム固定 |
170 | 195 | String title = rowMap.getTitle(column); |
@@ -226,4 +251,26 @@ public class DataViewTableModel extends KeyMatchedRowView implements TextKeyMatc | ||
226 | 251 | rowMap.remap(); |
227 | 252 | renumbering(rowMap); |
228 | 253 | } |
254 | + | |
255 | + public void setDisplayMode(DisplayMode displayMode) { | |
256 | + if (displayMode == null) { | |
257 | + throw new IllegalArgumentException(); | |
258 | + } | |
259 | + DisplayMode oldValue = this.displayMode; | |
260 | + this.displayMode = displayMode; | |
261 | + | |
262 | + if (displayMode != oldValue) { | |
263 | + propCng.firePropertyChange(PROPERTY_DISPLAY_MODE, oldValue, displayMode); | |
264 | + renumbering(rowMap); | |
265 | + } | |
266 | + } | |
267 | + | |
268 | + public DisplayMode getDisplayMode() { | |
269 | + return displayMode; | |
270 | + } | |
271 | + | |
272 | + @Override | |
273 | + public void renumbering(Map<RowKey, RowValues> dataMap) { | |
274 | + super.renumbering(new FilteredRowMap(dataMap, displayMode)); | |
275 | + } | |
229 | 276 | } |
@@ -0,0 +1,149 @@ | ||
1 | +/* | |
2 | + * To change this template, choose Tools | Templates | |
3 | + * and open the template in the editor. | |
4 | + */ | |
5 | +package textkeymatcher.ui.model; | |
6 | + | |
7 | +import java.beans.PropertyChangeEvent; | |
8 | +import java.beans.PropertyChangeListener; | |
9 | +import java.util.logging.Logger; | |
10 | +import org.jdesktop.application.AbstractBean; | |
11 | +import textkeymatcher.entity.DisplayMode; | |
12 | + | |
13 | +/** | |
14 | + * メニューのチェックボックス付きメニューアイテムでディスプレイモード(RowFilter)を切り替えるのに便利なように | |
15 | + * バインドをサポートします.<br> | |
16 | + * setFoo(boolean)では、引数enableがtrueである場合のみ設定されます.<br> | |
17 | + * 引数がfalseの場合は単に無視して解除しません.別のタイプがsetでenableされたときに変更されます.<br> | |
18 | + * | |
19 | + * @author osabe_masashi | |
20 | + */ | |
21 | +public class DisplayModeBinder extends AbstractBean { | |
22 | + | |
23 | + /** | |
24 | + * ロガー | |
25 | + */ | |
26 | + private static final Logger logger = Logger.getLogger(DisplayModeBinder.class.getName()); | |
27 | + | |
28 | + /** | |
29 | + * キーマッチャをもつ実体オブジェクト | |
30 | + */ | |
31 | + private DataViewTableModel tableModel; | |
32 | + | |
33 | + | |
34 | + /** | |
35 | + * 実体オブジェクトを設定します.<br> | |
36 | + * プロパティ変更リスナーがセットアップされます.<br> | |
37 | + * @param tableModel | |
38 | + */ | |
39 | + public void bindDataViewTableModel(DataViewTableModel tableModel) { | |
40 | + if (tableModel == null) { | |
41 | + throw new IllegalArgumentException(); | |
42 | + } | |
43 | + this.tableModel = tableModel; | |
44 | + this.tableModel.addPropertyChangeListener(new PropertyChangeListener() { | |
45 | + @Override | |
46 | + public void propertyChange(PropertyChangeEvent pce) { | |
47 | + tableModelPropertyChanged(pce); | |
48 | + } | |
49 | + }); | |
50 | + } | |
51 | + | |
52 | + /** | |
53 | + * キーマッチャが変更されたことを通知される.<br> | |
54 | + * @param pce プロパティ変更イベント | |
55 | + */ | |
56 | + protected void tableModelPropertyChanged(PropertyChangeEvent pce) { | |
57 | + String propertyName = pce.getPropertyName(); | |
58 | + if (DataViewTableModel.PROPERTY_DISPLAY_MODE.equals(propertyName)) { | |
59 | + changeDisplayMode( | |
60 | + (DisplayMode) pce.getOldValue(), | |
61 | + (DisplayMode) pce.getNewValue() | |
62 | + ); | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + protected DisplayMode getDisplayMode() { | |
67 | + if (tableModel == null) { | |
68 | + throw new IllegalStateException("先にsetDataViewTableModelで設定しておく必要があります."); | |
69 | + } | |
70 | + return tableModel.getDisplayMode(); | |
71 | + } | |
72 | + | |
73 | + protected void setDisplayMode(DisplayMode displayMode) { | |
74 | + if (tableModel == null) { | |
75 | + throw new IllegalStateException("先にsetDataViewTableModelで設定しておく必要があります."); | |
76 | + } | |
77 | + tableModel.setDisplayMode(displayMode); // thisにも変更通知がくることを想定 | |
78 | + } | |
79 | + | |
80 | + private void changeDisplayMode(DisplayMode oldValue, DisplayMode newValue) { | |
81 | + boolean oldAll = oldValue == DisplayMode.ALL; | |
82 | + boolean oldMatched = oldValue == DisplayMode.MATCHED; | |
83 | + boolean oldUnmatched = oldValue == DisplayMode.UNMATCHED; | |
84 | + boolean oldExistsFirst = oldValue == DisplayMode.EXISTS_FIRST_COLUMN; | |
85 | + boolean oldMissingFirst = oldValue == DisplayMode.MISSING_FIRST_COLUMN; | |
86 | + | |
87 | + boolean newAll = newValue == DisplayMode.ALL; | |
88 | + boolean newMatched = newValue == DisplayMode.MATCHED; | |
89 | + boolean newUnmatched = newValue == DisplayMode.UNMATCHED; | |
90 | + boolean newExistsFirst = newValue == DisplayMode.EXISTS_FIRST_COLUMN; | |
91 | + boolean newMissingFirst = newValue == DisplayMode.MISSING_FIRST_COLUMN; | |
92 | + | |
93 | + firePropertyChange("all", oldAll, newAll); | |
94 | + firePropertyChange("matched", oldMatched, newMatched); | |
95 | + firePropertyChange("unmatched", oldUnmatched, newUnmatched); | |
96 | + firePropertyChange("existsFirstColumn", oldExistsFirst, newExistsFirst); | |
97 | + firePropertyChange("missingFirstColumn", oldMissingFirst, newMissingFirst); | |
98 | + } | |
99 | + | |
100 | + public void setAll(boolean enable) { | |
101 | + if (enable) { | |
102 | + setDisplayMode(DisplayMode.ALL); | |
103 | + } | |
104 | + } | |
105 | + | |
106 | + public boolean isAll() { | |
107 | + return getDisplayMode() == DisplayMode.ALL; | |
108 | + } | |
109 | + | |
110 | + public void setMatched(boolean enable) { | |
111 | + if (enable) { | |
112 | + setDisplayMode(DisplayMode.MATCHED); | |
113 | + } | |
114 | + } | |
115 | + | |
116 | + public boolean isMatched() { | |
117 | + return getDisplayMode() == DisplayMode.MATCHED; | |
118 | + } | |
119 | + | |
120 | + public void setUnmatched(boolean enable) { | |
121 | + if (enable) { | |
122 | + setDisplayMode(DisplayMode.UNMATCHED); | |
123 | + } | |
124 | + } | |
125 | + | |
126 | + public boolean isUnmatched() { | |
127 | + return getDisplayMode() == DisplayMode.UNMATCHED; | |
128 | + } | |
129 | + | |
130 | + public void setExistsFirstColumn(boolean enable) { | |
131 | + if (enable) { | |
132 | + setDisplayMode(DisplayMode.EXISTS_FIRST_COLUMN); | |
133 | + } | |
134 | + } | |
135 | + | |
136 | + public boolean isExistsFirstColumn() { | |
137 | + return getDisplayMode() == DisplayMode.EXISTS_FIRST_COLUMN; | |
138 | + } | |
139 | + | |
140 | + public void setMissingFirstColumn(boolean enable) { | |
141 | + if (enable) { | |
142 | + setDisplayMode(DisplayMode.MISSING_FIRST_COLUMN); | |
143 | + } | |
144 | + } | |
145 | + | |
146 | + public boolean isMissingFirstColumn() { | |
147 | + return getDisplayMode() == DisplayMode.MISSING_FIRST_COLUMN; | |
148 | + } | |
149 | +} |
@@ -12,15 +12,16 @@ import org.jdesktop.application.AbstractBean; | ||
12 | 12 | import textkeymatcher.entity.KeyMatcher; |
13 | 13 | |
14 | 14 | /** |
15 | - * メニューのチェックボックス付きメニューアイテムでキーマッチングを切り替える場合に便利なようにバイントサポートするクラス.<br> | |
16 | - * setText/setTextIgnoreCase/setNumericでは、引数enableがtrueである場合のみ設定されます。 | |
15 | + * メニューのチェックボックス付きメニューアイテムでキーマッチングを切り替える場合に便利なように | |
16 | + * バイントサポートします.<br> | |
17 | + * setText/setTextIgnoreCase/setNumericでは、引数enableがtrueである場合のみ設定されます.<br> | |
17 | 18 | * 引数がfalseの場合は単に無視して解除しません.別のタイプがsetでenableされたときに変更されます.<br> |
18 | 19 | * @author seraphy |
19 | 20 | */ |
20 | 21 | public class KeyMatcherBinder extends AbstractBean { |
21 | 22 | |
22 | 23 | /** |
23 | - * ロガー` | |
24 | + * ロガー | |
24 | 25 | */ |
25 | 26 | private static final Logger logger = Logger.getLogger(KeyMatcherBinder.class.getName()); |
26 | 27 |