package logbook.gui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import logbook.config.ShipGroupConfig;
import logbook.config.bean.ShipGroupBean;
import logbook.config.bean.ShipGroupListBean;
import logbook.constants.AppConstants;
import logbook.data.Data;
import logbook.data.DataType;
import logbook.data.context.GlobalContext;
import logbook.dto.DockDto;
import logbook.dto.ShipDto;
import logbook.gui.logic.ShipGroupListener;
import logbook.gui.logic.ShipGroupObserver;
import logbook.gui.logic.TableItemCreator;
import logbook.gui.logic.TableRowHeader;
import logbook.internal.CondTiming;
import logbook.scripting.TableItemCreatorProxy;
import logbook.util.ReportUtils;
import logbook.util.SwtUtils;
import logbook.util.SwtUtils.TableDragAndDropListener;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.wb.swt.SWTResourceManager;
/**
* グループエディター
*
*/
public final class ShipFilterGroupDialog extends AbstractTableDialog implements ShipGroupListener {
private Text text;
private SashForm sashForm;
private Composite sideComposite;
private Composite mainComposite;
private Combo shipcombo;
private Table groupTable;
private Button btnAddShip;
private Button btnRemoveShip;
private final Map<String, ShipDto> shipmap = new HashMap<String, ShipDto>();
/** 現在表示しているグループ */
private GroupProperty property;
/**
* Create the dialog.
* @param parent
* @param menuItem
*/
public ShipFilterGroupDialog(Shell parent, MenuItem menuItem) {
super(parent, menuItem);
}
/**
* Create contents of the dialog.
*/
@Override
protected void createContentsBefore() {
GridLayout shellLayout = new GridLayout(1, false);
shellLayout.verticalSpacing = 1;
shellLayout.marginWidth = 1;
shellLayout.marginHeight = 1;
shellLayout.marginBottom = 1;
shellLayout.horizontalSpacing = 1;
this.shell.setLayout(shellLayout);
this.sashForm = new SashForm(this.shell, SWT.SMOOTH);
this.sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
this.sideComposite = new Composite(this.sashForm, SWT.NONE);
GridLayout sideLayout = new GridLayout(2, false);
sideLayout.verticalSpacing = 1;
sideLayout.marginWidth = 1;
sideLayout.marginHeight = 1;
sideLayout.marginBottom = 1;
sideLayout.horizontalSpacing = 1;
this.sideComposite.setLayout(sideLayout);
Button btnAdd = new Button(this.sideComposite, SWT.NONE);
btnAdd.addSelectionListener(new AddGroupAdapter(this));
btnAdd.setImage(SWTResourceManager.getImage(ShipFilterGroupDialog.class, AppConstants.R_ICON_ADD));
Button btnRemove = new Button(this.sideComposite, SWT.NONE);
btnRemove.addSelectionListener(new RemoveGroupAdapter(this));
btnRemove.setImage(SWTResourceManager.getImage(ShipFilterGroupDialog.class, AppConstants.R_ICON_DELETE));
final Table groupTable = this.groupTable = new Table(this.sideComposite, SWT.BORDER);
this.groupTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
this.groupTable.addSelectionListener(new GroupTableSelectionAdapter(this));
final TableColumn groupTableColumn = new TableColumn(this.groupTable, SWT.LEFT);
groupTableColumn.setText("グループ");
groupTableColumn.setMoveable(false);
groupTableColumn.setResizable(false);
this.groupTable.setHeaderVisible(false);
this.groupTable.addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event e) {
groupTableColumn.setWidth(groupTable.getClientArea().width);
}
});
SwtUtils.addItemDragAndDropMoveSupport(new Table[] { this.groupTable }, new TableDragAndDropListener() {
@Override
public boolean canDragSource(TableItem source) {
return true;
}
@Override
public TableItem create(Table table, TableItem source, int index) {
// 実際のリストを操作
List<ShipGroupBean> list = ShipGroupConfig.get().getGroup();
GroupProperty prop = (GroupProperty) source.getData();
int oldIndex = list.indexOf(prop.getShipGroupBean());
list.add(index, prop.getShipGroupBean());
list.remove(oldIndex < index ? oldIndex : oldIndex + 1);
// テーブルアイテム作成
TableItem item = new TableItem(groupTable, SWT.NONE, index);
prop.setTreeItem(item);
item.setText(source.getText());
item.setData(prop);
return item;
}
@Override
public void finished(TableItem newItem) {
ShipGroupObserver.listChanged();
}
@Override
public String tableItemToString(TableItem item) {
return item.getText();
}
});
ShipGroupListBean shipGroupList = ShipGroupConfig.get();
for (ShipGroupBean bean : shipGroupList.getGroup()) {
TableItem groupItem = new TableItem(this.groupTable, SWT.NONE);
//groupItem.setImage(SWTResourceManager
// .getImage(ShipFilterGroupDialog.class, AppConstants.R_ICON_FOLDER));
groupItem.setText(bean.getName());
groupItem.setData(new GroupProperty(bean, groupItem));
}
this.mainComposite = new Composite(this.sashForm, SWT.NONE);
GridLayout mainLayout = new GridLayout(4, false);
mainLayout.verticalSpacing = 1;
mainLayout.marginWidth = 1;
mainLayout.marginHeight = 1;
mainLayout.marginBottom = 1;
mainLayout.horizontalSpacing = 1;
this.mainComposite.setLayout(mainLayout);
this.text = new Text(this.mainComposite, SWT.BORDER);
this.text.addModifyListener(new ModifyNameAdapter(this));
this.text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 4, 1));
this.text.setEnabled(false);
}
/**
* Create contents of the dialog.
*/
@Override
protected void createContents() {
this.table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
this.shipcombo = new Combo(this.mainComposite, SWT.READ_ONLY);
this.setShipComboData();
this.shipcombo.setEnabled(false);
this.btnAddShip = new Button(this.mainComposite, SWT.NONE);
this.btnAddShip.setText("追加");
this.btnAddShip.addSelectionListener(new AddShipAdapter(this));
this.btnAddShip.setEnabled(false);
this.btnRemoveShip = new Button(this.mainComposite, SWT.NONE);
this.btnRemoveShip.setText("除去");
this.btnRemoveShip.addSelectionListener(new RemoveShipAdapter(this));
this.btnRemoveShip.setEnabled(false);
Button updateShip = new Button(this.mainComposite, SWT.NONE);
updateShip.setText("更新");
updateShip.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ShipFilterGroupDialog.this.setShipComboData();
}
});
this.sashForm.setWeights(new int[] { 2, 5 });
new MenuItem(this.tablemenu, SWT.SEPARATOR);
final MenuItem[] addFleetShipItems = new MenuItem[4];
for (int i = 1; i <= 4; ++i) {
MenuItem addFleetMenu = addFleetShipItems[i - 1] = new MenuItem(this.tablemenu, SWT.NONE);
addFleetMenu.setText("第" + i + "艦隊の艦娘を追加");
addFleetMenu.addSelectionListener(new AddFleetShipAdapter(this, Integer.toString(i)));
}
this.table.addListener(SWT.MenuDetect, new Listener() {
@Override
public void handleEvent(Event event) {
for (int i = 1; i <= 4; ++i) {
DockDto dto = GlobalContext.getDock(Integer.toString(i));
addFleetShipItems[i - 1].setEnabled(
(ShipFilterGroupDialog.this.property != null)
&& (dto != null)
&& (dto.getShips().size() > 0));
}
}
});
SwtUtils.addItemDragAndDropMoveSupport(new Table[] { this.table }, new TableDragAndDropListener() {
@Override
public boolean canDragSource(TableItem source) {
// ソート順なし かつ 1つのみ選択状態
return (ShipFilterGroupDialog.this.property != null) &&
(ShipFilterGroupDialog.this.config.getSortKeys()[0] == null) &&
(ShipFilterGroupDialog.this.table.getSelection().length == 1);
}
@Override
public TableItem create(Table table, TableItem source, int index) {
// 実際のリストを操作
if (ShipFilterGroupDialog.this.property != null) {
Set<Integer> set = ShipFilterGroupDialog.this.property.getShipGroupBean().getShips();
ShipDto ship = (ShipDto) source.getData();
Integer[] origarray = set.toArray(new Integer[0]);
set.clear();
for (int i = 0; i < origarray.length; ++i) {
if (i == index) {
set.add(ship.getId());
}
if (origarray[i] != ship.getId()) {
set.add(origarray[i]);
}
}
set.add(ship.getId()); // 最後に追加する場合
}
// reloadが走るのでここではダミーを返しておく
return source;
}
@Override
public void finished(TableItem newItem) {
if (ShipFilterGroupDialog.this.property != null) {
ShipGroupObserver.groupShipChanged(ShipFilterGroupDialog.this.property.getShipGroupBean());
}
}
@Override
public String tableItemToString(TableItem item) {
return ((ShipDto) item.getData()).getFullName();
}
});
ShipGroupObserver.addListener(this);
this.table.addListener(SWT.Dispose, new Listener() {
@Override
public void handleEvent(Event event) {
ShipGroupObserver.removeListener(ShipFilterGroupDialog.this);
}
});
}
@Override
protected Composite getTableParent() {
return this.mainComposite;
}
@Override
protected String getTitleMain() {
return "グループエディター";
}
@Override
protected Point getSize() {
return SwtUtils.DPIAwareSize(new Point(600, 350));
}
@Override
protected String[] getTableHeader() {
return new String[] { "", "ID", "艦隊", "名前", "艦種", "Lv", "疲労" };
}
@Override
protected void updateTableBody() {
List<Comparable[]> body = new ArrayList<Comparable[]>();
CondTiming condTiming = GlobalContext.getCondTiming();
if (this.property != null) {
List<ShipDto> shipList = this.property.getShipList();
for (int i = 0; i < shipList.size(); i++) {
ShipDto ship = shipList.get(i);
body.add(new Comparable[] {
new TableRowHeader(i + 1, ship),
ship.getId(),
ship.getFleetid(),
ship.getName(),
ship.getType(),
ship.getLv(),
ship.getEstimatedCond(condTiming)
});
}
}
this.body = body;
}
@Override
protected TableItemCreator getTableItemCreator() {
return TableItemCreatorProxy.get(AppConstants.SHIPGROUPTABLE_PREFIX);
/*
return new TableItemCreator() {
@Override
public void init() {
}
@Override
public TableItem create(Table table, Comparable[] text, int count) {
ShipDto ship = (ShipDto) ((TableRowHeader) text[0]).get();
TableItem item = new TableItem(table, SWT.NONE);
// 偶数行に背景色を付ける
if ((count % 2) != 0) {
item.setBackground(SWTResourceManager.getColor(AppConstants.ROW_BACKGROUND));
}
item.setBackground(6, CreateReportLogic.getTableCondColor(ship.getEstimatedCond()));
item.setText(ReportUtils.toStringArray(text));
return item;
}
};
*/
}
@Override
protected void reloadTable() {
super.reloadTable();
// 名前・ボタンの状態をセットします
if (this.property != null) {
ShipGroupBean group = this.property.getShipGroupBean();
this.text.setText(group.getName());
this.text.setEnabled(true);
this.shipcombo.setEnabled(true);
this.btnAddShip.setEnabled(true);
this.btnRemoveShip.setEnabled(true);
} else {
this.text.setText("");
this.text.setEnabled(false);
this.shipcombo.setEnabled(false);
this.btnAddShip.setEnabled(false);
this.btnRemoveShip.setEnabled(false);
}
}
/**
* コンボボックスに艦娘をセットします
*
* @param combo
*/
private void setShipComboData() {
// コンボボックスから全ての艦娘を削除
this.shipcombo.removeAll();
// 表示用文字列と艦娘の紐付けを削除
this.shipmap.clear();
// 艦娘IDの最大を取得してゼロ埋め長さを算出
int maxshipid = 0;
for (ShipDto ship : GlobalContext.getShipMap().values()) {
maxshipid = Math.max(ship.getId(), maxshipid);
}
int padlength = String.valueOf(maxshipid).length();
// 表示用文字列と艦娘の紐付けを追加
for (ShipDto ship : GlobalContext.getShipMap().values()) {
this.shipmap.put(this.getShipLabel(ship, padlength), ship);
}
// 艦娘を経験値順でソート
List<ShipDto> ships = new ArrayList<ShipDto>(this.shipmap.values());
Collections.sort(ships, new Comparator<ShipDto>() {
@Override
public int compare(ShipDto o1, ShipDto o2) {
return Integer.compare(o2.getExp(), o1.getExp());
}
});
// コンボボックスに追加
for (int i = 0; i < ships.size(); i++) {
String key = this.getShipLabel(ships.get(i), padlength);
this.shipcombo.add(key);
}
// コントロールを再配置
this.shipcombo.pack();
this.shipcombo.getParent().layout();
}
/**
* 艦娘のプルダウン表示用文字列を作成します
*
* @param ship
* @param padlength
* @return
*/
private String getShipLabel(ShipDto ship, int padlength) {
return new StringBuilder().append(StringUtils.leftPad(String.valueOf(ship.getId()), padlength, '0'))
.append(": ").append(ship.getName()).append(" (Lv").append(ship.getLv() + ")").toString();
}
/**
* グループを追加するときに呼び出されるアダプター
*
*/
private static final class AddGroupAdapter extends SelectionAdapter {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
/**
* コンストラクター
*/
public AddGroupAdapter(ShipFilterGroupDialog dialog) {
this.dialog = dialog;
}
private ShipGroupBean createNewGroup(List<ShipGroupBean> list) {
Set<Integer> idSet = new HashSet<Integer>();
for (ShipGroupBean shipGroup : list) {
idSet.add(shipGroup.getId());
}
Random rnd = new Random(System.currentTimeMillis());
// 一意のIDを生成する
int newId = rnd.nextInt();
while (idSet.contains(newId) || (newId == 0))
newId = rnd.nextInt();
ShipGroupBean bean = new ShipGroupBean();
bean.setId(newId);
bean.setName("新規グループ");
list.add(bean);
return bean;
}
@Override
public void widgetSelected(SelectionEvent e) {
List<ShipGroupBean> shipGroupList = ShipGroupConfig.get().getGroup();
ShipGroupBean bean = this.createNewGroup(shipGroupList);
TableItem item = new TableItem(this.dialog.groupTable, SWT.NONE);
//item.setImage(SWTResourceManager.getImage(ShipFilterGroupDialog.class, AppConstants.R_ICON_FOLDER));
item.setText(bean.getName());
item.setData(new GroupProperty(bean, item));
ShipGroupObserver.listChanged();
}
}
/**
* グループを除去するときに呼び出されるアダプター
*
*/
private static final class RemoveGroupAdapter extends SelectionAdapter {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
/**
* コンストラクター
*/
public RemoveGroupAdapter(ShipFilterGroupDialog dialog) {
this.dialog = dialog;
}
@Override
public void widgetSelected(SelectionEvent e) {
if (this.dialog.property != null) {
ShipGroupBean target = this.dialog.property.getShipGroupBean();
MessageBox box = new MessageBox(this.dialog.shell, SWT.YES | SWT.NO
| SWT.ICON_QUESTION);
box.setText("グループを除去");
box.setMessage("「" + target.getName() + "」を除去しますか?");
if (box.open() == SWT.YES) {
List<ShipGroupBean> shipGroupList = ShipGroupConfig.get().getGroup();
for (int i = 0; i < shipGroupList.size(); i++) {
if (shipGroupList.get(i) == target) {
shipGroupList.remove(i);
}
}
this.dialog.text.setText("");
this.dialog.property.getTreeItem().dispose();
this.dialog.property = null;
ShipGroupObserver.listChanged();
}
}
}
}
/**
* 名前を変更した時に呼び出されるアダプター
*
*/
private static final class ModifyNameAdapter implements ModifyListener {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
/**
* コンストラクター
*/
public ModifyNameAdapter(ShipFilterGroupDialog dialog) {
this.dialog = dialog;
}
@Override
public void modifyText(ModifyEvent e) {
if (this.dialog.property != null) {
ShipGroupBean group = this.dialog.property.getShipGroupBean();
String text = this.dialog.text.getText();
String groupName = group.getName();
if (!text.equals(groupName)) { // 変わった時だけ
this.dialog.property.getTreeItem().setText(text);
group.setName(text);
ShipGroupObserver.groupNameChanged(group);
}
}
}
}
/**
* ツリーをクリックした時に呼び出されるアダプター
*
*/
private static final class GroupTableSelectionAdapter extends SelectionAdapter {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
/**
* コンストラクター
*/
public GroupTableSelectionAdapter(ShipFilterGroupDialog dialog) {
this.dialog = dialog;
}
@Override
public void widgetSelected(SelectionEvent e) {
if (e.item != null) {
Object data = e.item.getData();
if (data instanceof GroupProperty) {
this.dialog.property = (GroupProperty) data;
} else {
this.dialog.property = null;
}
this.dialog.reloadTable();
}
}
}
/**
* 艦娘を追加するときに呼び出されるアダプター
*
*/
private static final class AddShipAdapter extends SelectionAdapter {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
/**
* コンストラクター
*/
public AddShipAdapter(ShipFilterGroupDialog dialog) {
this.dialog = dialog;
}
@Override
public void widgetSelected(SelectionEvent e) {
if (this.dialog.property != null) {
if (this.dialog.shipcombo.getSelectionIndex() >= 0) {
ShipGroupBean target = this.dialog.property.getShipGroupBean();
ShipDto ship = this.dialog.shipmap.get(this.dialog.shipcombo.getItem(this.dialog.shipcombo
.getSelectionIndex()));
target.getShips().add(ship.getId());
ShipGroupObserver.groupShipChanged(target);
}
}
}
}
/**
* 艦娘を除去するときに呼び出されるアダプター
*
*/
private static final class RemoveShipAdapter extends SelectionAdapter {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
/**
* コンストラクター
*/
public RemoveShipAdapter(ShipFilterGroupDialog dialog) {
this.dialog = dialog;
}
@Override
public void widgetSelected(SelectionEvent e) {
if (this.dialog.property != null) {
ShipGroupBean bean = this.dialog.property.getShipGroupBean();
TableItem[] items = this.dialog.table.getSelection();
List<Integer> ids = new ArrayList<>();
List<String> name = new ArrayList<>();
for (TableItem tableItem : items) {
ShipDto ship = (ShipDto) tableItem.getData();
ids.add(ship.getId());
name.add(ship.getFriendlyName());
}
MessageBox box = new MessageBox(this.dialog.shell, SWT.YES | SWT.NO
| SWT.ICON_QUESTION);
box.setText("選択した艦娘をグループから除去");
box.setMessage("「" + StringUtils.join(name, ",") + "」をグループから除去しますか?");
if (box.open() == SWT.YES) {
for (Integer id : ids) {
bean.getShips().remove(id);
}
ShipGroupObserver.groupShipChanged(bean);
}
}
}
}
/**
* 艦娘を除去するときに呼び出されるアダプター
*
*/
private static final class AddFleetShipAdapter extends SelectionAdapter {
/** ダイアログ */
private final ShipFilterGroupDialog dialog;
private final String fleetid;
/**
* コンストラクター
*/
public AddFleetShipAdapter(ShipFilterGroupDialog dialog, String fleetid) {
this.dialog = dialog;
this.fleetid = fleetid;
}
@Override
public void widgetSelected(SelectionEvent e) {
if (this.dialog.property != null) {
ShipGroupBean bean = this.dialog.property.getShipGroupBean();
DockDto dto = GlobalContext.getDock(this.fleetid);
if ((dto != null) && (dto.getShips().size() > 0)) {
List<Integer> ids = new ArrayList<>();
List<String> name = new ArrayList<>();
for (ShipDto ship : dto.getShips()) {
ids.add(ship.getId());
name.add(ship.getFriendlyName());
}
MessageBox box = new MessageBox(this.dialog.shell, SWT.YES | SWT.NO
| SWT.ICON_QUESTION);
box.setText("選択した艦娘をグループに追加");
box.setMessage("「" + StringUtils.join(name, ",") + "」をグループに追加しますか?");
if (box.open() == SWT.YES) {
for (Integer id : ids) {
bean.getShips().add(id);
}
ShipGroupObserver.groupShipChanged(bean);
}
}
}
}
}
/**
* テーブルに表示する所有艦娘のグループ
*
*/
private static final class GroupProperty {
/** 所有艦娘のグループ */
private final ShipGroupBean shipGroup;
/** TreeItem */
private TableItem item;
/**
* コンストラクター
*
* @param shipGroup 所有艦娘のグループ
* @param item TreeItem
*/
public GroupProperty(ShipGroupBean shipGroup, TableItem item) {
this.shipGroup = shipGroup;
this.item = item;
}
/**
* 所有艦娘のグループを取得します
*
* @return 所有艦娘のグループ
*/
public ShipGroupBean getShipGroupBean() {
return this.shipGroup;
}
/**
* TreeItemを取得します
* @return TreeItem
*/
public TableItem getTreeItem() {
return this.item;
}
/**
* @param item2
*/
public void setTreeItem(TableItem item2) {
this.item = item2;
}
/**
* 艦娘のリストを取得します
*
* @return 艦娘のリスト
*/
public List<ShipDto> getShipList() {
List<ShipDto> ships = new ArrayList<ShipDto>();
Map<Integer, ShipDto> shipMap = GlobalContext.getShipMap();
for (int id : this.shipGroup.getShips()) {
ShipDto ship = shipMap.get(id);
if (ship != null) {
ships.add(ship);
}
}
return ships;
}
}
@Override
public void listChanged() {
// 自分で変更しているので何もしない
}
@Override
public void groupNameChanged(ShipGroupBean group) {
// 自分で変更しているので何もしない
}
@Override
public void groupShipChanged(ShipGroupBean group) {
if ((this.property != null) && (this.property.getShipGroupBean() == group)) {
this.reloadTable();
}
}
/**
* 更新する必要のあるデータ
*/
@Override
public void update(DataType type, Data data) {
if (ReportUtils.isShipUpdate(type)) {
this.needsUpdate = true;
}
}
}