import java.awt.Component;
import java.awt.event.ActionListener;
-import java.util.EventListener;
-import java.util.LinkedList;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
-import javax.swing.event.EventListenerList;
import jp.sfjp.jindolf.data.DialogPref;
import jp.sfjp.jindolf.data.Period;
import jp.sfjp.jindolf.data.Village;
* タブを用いて村情報と各Periodを切り替え表示するためのコンポーネント。
*/
@SuppressWarnings("serial")
-public class TabBrowser extends JTabbedPane{
+public final class TabBrowser extends JTabbedPane{
private Village village;
private FontInfo fontInfo;
private DialogPref dialogPref;
- private final EventListenerList thisListenerList =
- new EventListenerList();
-
/**
* コンストラクタ。
addTab("村情報", new JScrollPane(this.villageInfo));
- setVillage(null);
+ initTab();
return;
}
}
/**
+ * タブ初期化。
+ *
+ * <p>Periodタブは全て消え村情報タブのみになる。
+ */
+ private void initTab(){
+ modifyTabCount(0);
+
+ updateVillageInfo();
+ selectVillageInfoTab();
+
+ repaint();
+ revalidate();
+
+ return;
+ }
+
+ /**
+ * PeriodViewインスタンスを生成する。
+ *
+ * <p>フォント設定、会話表示設定、各種リスナの設定が行われる。
+ *
+ * @param period Period
+ * @return PeriodViewインスタンス
+ */
+ private PeriodView buildPeriodView(Period period){
+ PeriodView result;
+
+ result = new PeriodView(period);
+ result.setFontInfo(this.fontInfo);
+ result.setDialogPref(this.dialogPref);
+
+ Discussion discussion = result.getDiscussion();
+ for(ActionListener listener : getActionListeners()){
+ discussion.addActionListener(listener);
+ }
+ for(AnchorHitListener listener : getAnchorHitListeners()){
+ discussion.addAnchorHitListener(listener);
+ }
+
+ return result;
+ }
+
+ /**
* 新規に村を設定する。
*
+ * <p>村のPeriod数に応じてタブの数は変化する。
+ *
* @param village 新しい村
*/
public final void setVillage(Village village){
- if(village == null){
- if(this.village != null){
- this.village.unloadPeriods();
- }
- this.village = null;
- selectVillageInfoTab();
- modifyTabCount(0);
- updateVillageInfo();
+ Village oldVillage = this.village;
+ if(oldVillage != null && village != oldVillage){
+ oldVillage.unloadPeriods();
+ }
+
+ this.village = village;
+ if(this.village == null){
+ initTab();
return;
- }else if(village != this.village){
- selectVillageInfoTab();
}
- if(this.village != null){
- this.village.unloadPeriods();
+ if(this.village != oldVillage){
+ selectVillageInfoTab();
}
- this.village = village;
updateVillageInfo();
for(int periodDays = 0; periodDays < periodNum; periodDays++){
Period period = this.village.getPeriod(periodDays);
+ PeriodView periodView = buildPeriodView(period);
+
int tabIndex = periodDaysToTabIndex(periodDays);
- PeriodView periodView = getPeriodView(tabIndex);
- if(periodView == null){
- periodView = new PeriodView(period);
- periodView.setFontInfo(this.fontInfo);
- periodView.setDialogPref(this.dialogPref);
- setComponentAt(tabIndex, periodView);
- Discussion discussion = periodView.getDiscussion();
- for(ActionListener listener : getActionListeners()){
- discussion.addActionListener(listener);
- }
- for(AnchorHitListener listener : getAnchorHitListeners()){
- discussion.addAnchorHitListener(listener);
- }
- }
+ setComponentAt(tabIndex, periodView);
+
String caption = period.getCaption();
setTitleAt(tabIndex, caption);
- if(period == periodView.getPeriod()) continue;
- periodView.setPeriod(period);
}
+ repaint();
+ revalidate();
+
return;
}
/**
* 指定した数のPeriodが収まるよう必要十分なタブ数を用意する。
*
- * @param periods Periodの数
+ * @param periods Periodの数(エピローグを含む)
*/
private void modifyTabCount(int periods){ // TODO 0でも大丈夫?
int maxPeriodDays = periods - 1;
for(;;){ // 短ければタブ追加
- int maxTabIndex = getTabCount() - 1;
- if(tabIndexToPeriodDays(maxTabIndex) >= maxPeriodDays) break;
- String title = "";
- Component component = new JPanel();
- addTab(title, component);
+ int lastTabIndex = getTabCount() - 1;
+ if(tabIndexToPeriodDays(lastTabIndex) >= maxPeriodDays) break;
+ String tabTitle = "";
+ Component dummy = new JPanel();
+ addTab(tabTitle, dummy);
}
for(;;){ // 長ければ余分なタブ削除
- int maxTabIndex = getTabCount() - 1;
- if(tabIndexToPeriodDays(maxTabIndex) <= maxPeriodDays) break;
- remove(maxTabIndex);
+ int lastTabIndex = getTabCount() - 1;
+ if(tabIndexToPeriodDays(lastTabIndex) <= maxPeriodDays) break;
+ remove(lastTabIndex);
}
return;
/**
* Period日付指定からタブインデックス値への変換。
*
+ * <p>エピローグ(0日目)のタブインデックスは1。
+ * 1日目Periodのタブインデックスは2。
+ *
* @param days Period日付指定
- * @return タブインデックス
+ * @return タブインデックス。存在しないタブの場合は負の値。
*/
public int periodDaysToTabIndex(int days){
+ if(days < 0) return -1;
int tabIndex = days+1;
if(tabIndex >= getTabCount()) return -1;
return tabIndex;
/**
* タブインデックス値からPeriod日付指定への変換。
*
+ * <p>エピローグタブのPeriod日付は0。
+ * 1日目PeriodタブのPeriod日付は1。
+ *
* @param tabIndex タブインデックス
- * @return Period日付指定
+ * @return Period日付指定。存在しないタブの場合は負の値。
*/
private int tabIndexToPeriodDays(int tabIndex){
- if(tabIndex >= getTabCount()) return - 1;
+ if(tabIndex < 0) return -1;
+ if(tabIndex >= getTabCount()) return -1;
int days = tabIndex - 1;
return days;
}
* @return PeriodView の List
*/
public List<PeriodView> getPeriodViewList(){
- List<PeriodView> result = new LinkedList<>();
-
int tabCount = getTabCount();
- for(int tabIndex = 0; tabIndex <= tabCount - 1; tabIndex++){
+ List<PeriodView> result = new ArrayList<>(tabCount - 1);
+
+ for(int tabIndex = 1; tabIndex < tabCount; tabIndex++){
Component component = getComponent(tabIndex);
- if(component == null) continue;
- if( ! (component instanceof PeriodView) ) continue;
PeriodView periodView = (PeriodView) component;
result.add(periodView);
}
public PeriodView getPeriodView(int tabIndex){
if(tabIndexToPeriodDays(tabIndex) < 0) return null;
if(tabIndex >= getTabCount()) return null;
- Component component = getComponentAt(tabIndex);
- if(component == null) return null;
+ Component component = getComponentAt(tabIndex);
if( ! (component instanceof PeriodView) ) return null;
PeriodView periodView = (PeriodView) component;
* @param fontInfo フォント
*/
public void setFontInfo(FontInfo fontInfo){
+ Objects.nonNull(fontInfo);
this.fontInfo = fontInfo;
- for(int tabIndex = 0; tabIndex <= getTabCount() - 1; tabIndex++){
- PeriodView periodView = getPeriodView(tabIndex);
- if(periodView == null) continue;
+ getPeriodViewList().forEach((periodView) -> {
periodView.setFontInfo(this.fontInfo);
- }
+ });
return;
}
* @param dialogPref 発言表示設定
*/
public void setDialogPref(DialogPref dialogPref){
+ Objects.nonNull(dialogPref);
this.dialogPref = dialogPref;
- for(int tabIndex = 0; tabIndex <= getTabCount() - 1; tabIndex++){
- PeriodView periodView = getPeriodView(tabIndex);
- if(periodView == null) continue;
+ getPeriodViewList().forEach((periodView) -> {
periodView.setDialogPref(this.dialogPref);
- }
+ });
return;
}
* @param listener リスナー
*/
public void addActionListener(ActionListener listener){
- this.thisListenerList.add(ActionListener.class, listener);
+ this.listenerList.add(ActionListener.class, listener);
if(this.village == null) return;
- int periodNum = this.village.getPeriodSize();
- for(int periodDays = 0; periodDays < periodNum; periodDays++){
- int tabIndex = periodDaysToTabIndex(periodDays);
- Discussion discussion = getDiscussion(tabIndex);
- if(discussion == null) continue;
+
+ getPeriodViewList().forEach((periodView) -> {
+ Discussion discussion = periodView.getDiscussion();
discussion.addActionListener(listener);
- }
+ });
return;
}
* @param listener リスナー
*/
public void removeActionListener(ActionListener listener){
- this.thisListenerList.remove(ActionListener.class, listener);
+ this.listenerList.remove(ActionListener.class, listener);
if(this.village == null) return;
- int periodNum = this.village.getPeriodSize();
- for(int periodDays = 0; periodDays < periodNum; periodDays++){
- int tabIndex = periodDaysToTabIndex(periodDays);
- Discussion discussion = getDiscussion(tabIndex);
- if(discussion == null) continue;
+
+ getPeriodViewList().forEach((periodView) -> {
+ Discussion discussion = periodView.getDiscussion();
discussion.removeActionListener(listener);
- }
+ });
return;
}
* @return すべてのActionListener
*/
public ActionListener[] getActionListeners(){
- return this.thisListenerList.getListeners(ActionListener.class);
+ return getListeners(ActionListener.class);
}
/**
* @param listener リスナー
*/
public void addAnchorHitListener(AnchorHitListener listener){
- this.thisListenerList.add(AnchorHitListener.class, listener);
+ this.listenerList.add(AnchorHitListener.class, listener);
if(this.village == null) return;
- int periodNum = this.village.getPeriodSize();
- for(int periodDays = 0; periodDays < periodNum; periodDays++){
- int tabIndex = periodDaysToTabIndex(periodDays);
- Discussion discussion = getDiscussion(tabIndex);
- if(discussion == null) continue;
+
+ getPeriodViewList().forEach((periodView) -> {
+ Discussion discussion = periodView.getDiscussion();
discussion.addAnchorHitListener(listener);
- }
+ });
return;
}
* @param listener リスナー
*/
public void removeAnchorHitListener(AnchorHitListener listener){
- this.thisListenerList.remove(AnchorHitListener.class, listener);
+ this.listenerList.remove(AnchorHitListener.class, listener);
if(this.village == null) return;
- int periodNum = this.village.getPeriodSize();
- for(int periodDays = 0; periodDays < periodNum; periodDays++){
- int tabIndex = periodDaysToTabIndex(periodDays);
- Discussion discussion = getDiscussion(tabIndex);
- if(discussion == null) continue;
+
+ getPeriodViewList().forEach((periodView) -> {
+ Discussion discussion = periodView.getDiscussion();
discussion.removeAnchorHitListener(listener);
- }
+ });
return;
}
* @return すべてのAnchorHitListener
*/
public AnchorHitListener[] getAnchorHitListeners(){
- return this.thisListenerList.getListeners(AnchorHitListener.class);
- }
-
- /**
- * {@inheritDoc}
- *
- * @param <T> {@inheritDoc}
- * @param listenerType {@inheritDoc}
- * @return {@inheritDoc}
- */
- @Override
- public <T extends EventListener> T[] getListeners(Class<T> listenerType){
- T[] result;
- result = this.thisListenerList.getListeners(listenerType);
-
- if(result.length <= 0){
- result = super.getListeners(listenerType);
- }
-
- return result;
+ return getListeners(AnchorHitListener.class);
}
}