package logbook.gui;
import java.util.ArrayList;
import java.util.List;
import logbook.config.AppConfig;
import logbook.config.ShipGroupConfig;
import logbook.config.bean.ShipFilterPanelConfigBean;
import logbook.config.bean.ShipGroupBean;
import logbook.constants.AppConstants;
import logbook.data.Data;
import logbook.data.DataType;
import logbook.dto.ShipDto;
import logbook.dto.ShipFilterDto;
import logbook.gui.logic.CreateReportLogic;
import logbook.gui.logic.ShipGroupListener;
import logbook.gui.logic.ShipGroupObserver;
import logbook.gui.logic.TableItemCreator;
import logbook.gui.widgets.ShipFilterComposite;
import logbook.scripting.TableItemCreatorProxy;
import logbook.util.ReportUtils;
import logbook.util.SwtUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableItem;
/**
* 所有艦娘一覧テーブル
*
*/
public final class ShipTable extends AbstractTableDialog implements ShipGroupListener {
/** 何番目か */
private final int index;
/** 成長余地 */
private boolean specdiff = false;
/** 装備上昇分分離 */
private boolean specseparate = false;
/** フィルター */
private ShipFilterDto filter = null;
private ShipFilterComposite filterCompo;
private MenuItem switchdiff;
private MenuItem switchdiff2;
private MenuItem switchseparate;
private MenuItem switchseparate2;
private MenuItem addGroupCascade;
private MenuItem removeGroupCascade;
private FilterMenu filterMenu;
/**
* @param parent
*/
public ShipTable(Shell parent, MenuItem menuItem, int index) {
super(parent, menuItem);
this.index = index;
}
/**
* Open the dialog.
*/
@Override
public void open() {
if (this.isWindowInitialized()) {
// フィルタパネルの内容を更新しておく
this.filterCompo.setRedraw(false);
this.filterCompo.updateContents(this.filter);
this.filterCompo.layout();
this.filterCompo.setRedraw(true);
}
super.open();
}
/**
* フィルターを設定する
* @param filter フィルター
*/
public void updateFilter(ShipFilterDto filter, boolean applyToMenu) {
this.filter = filter;
this.reloadTable();
this.shell.setText(this.getTitle());
if (applyToMenu) {
this.filterMenu.applyFilter(filter);
}
}
public void updateFilter(ShipFilterDto filter) {
this.updateFilter(filter, false);
}
@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.filterCompo = new ShipFilterComposite(this);
this.filterCompo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
}
@Override
protected void createContents() {
SelectionListener switchDiffListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ShipTable.this.switchSpecDiff((MenuItem) e.getSource());
}
};
SelectionListener switchSeparateListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ShipTable.this.switchSpecSeparate((MenuItem) e.getSource());
}
};
this.table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
// メニューバーに追加する
this.filterMenu = new FilterMenu(this.menubar);
// 成長の余地を表示メニュー
new MenuItem(this.opemenu, SWT.SEPARATOR);
this.switchdiff = new MenuItem(this.opemenu, SWT.CHECK);
this.switchdiff.setText("成長の余地を表示");
this.switchdiff.setSelection(this.specdiff);
this.switchdiff.addSelectionListener(switchDiffListener);
this.switchseparate = new MenuItem(this.opemenu, SWT.CHECK);
this.switchseparate.setText("装備上昇分を分離表示");
this.switchseparate.setSelection(this.specseparate);
this.switchseparate.addSelectionListener(switchSeparateListener);
if (!this.isNoMenubar()) {
// セパレータ
new MenuItem(this.tablemenu, SWT.SEPARATOR);
// 成長の余地を表示メニュー
this.switchdiff2 = new MenuItem(this.tablemenu, SWT.CHECK);
this.switchdiff2.setText("成長の余地を表示");
this.switchdiff2.setSelection(this.specdiff);
this.switchdiff2.addSelectionListener(switchDiffListener);
this.switchseparate2 = new MenuItem(this.tablemenu, SWT.CHECK);
this.switchseparate2.setText("装備上昇分を分離表示");
this.switchseparate2.setSelection(this.specseparate);
this.switchseparate2.addSelectionListener(switchSeparateListener);
}
// セパレータ
new MenuItem(this.tablemenu, SWT.SEPARATOR);
this.addGroupCascade = new MenuItem(this.tablemenu, SWT.CASCADE);
this.addGroupCascade.setText("選択した艦娘をグループに追加(&A)");
this.removeGroupCascade = new MenuItem(this.tablemenu, SWT.CASCADE);
this.removeGroupCascade.setText("選択した艦娘をグループから除去(&D)");
MenuItem idCopy = new MenuItem(this.tablemenu, SWT.NONE);
idCopy.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
StringBuilder sb = new StringBuilder();
for (TableItem item : ShipTable.this.table.getSelection()) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(String.valueOf(((ShipDto) item.getData()).getId()));
}
Clipboard clipboard = new Clipboard(Display.getDefault());
clipboard.setContents(new Object[] { sb.toString() }, new Transfer[] { TextTransfer.getInstance() });
}
});
idCopy.setText("艦娘個人IDをコピー(&1)");
MenuItem shipCopy = new MenuItem(this.tablemenu, SWT.NONE);
shipCopy.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
StringBuilder sb = new StringBuilder();
for (TableItem item : ShipTable.this.table.getSelection()) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(((ShipDto) item.getData()).getName());
}
Clipboard clipboard = new Clipboard(Display.getDefault());
clipboard.setContents(new Object[] { sb.toString() }, new Transfer[] { TextTransfer.getInstance() });
}
});
shipCopy.setText("艦娘の名前をコピー(&2)");
// フィルタを復元
ShipFilterDto[] shipFilters = AppConfig.get().getShipFilters();
if ((shipFilters != null) && (shipFilters.length > this.index)) {
this.filter = shipFilters[this.index];
}
if (this.filter == null) {
this.filter = new ShipFilterDto();
}
if ((this.filter.group == null) && (this.filter.groupId != 0)) {
for (ShipGroupBean group : ShipGroupConfig.get().getGroup()) {
if (group.getId() == this.filter.groupId) {
this.filter.group = group;
break;
}
}
}
this.listChanged();
ShipFilterPanelConfigBean panelConfig = this.getPanelConfig();
this.filterCompo.updateContents(this.filter, panelConfig.panelVisible, panelConfig.etcVisible);
this.filterMenu.applyFilter(this.filter);
this.filterMenu.setPanelVisible(panelConfig.panelVisible, panelConfig.etcVisible);
ShipGroupObserver.addListener(this);
this.table.addListener(SWT.Dispose, new Listener() {
@Override
public void handleEvent(Event event) {
ShipGroupObserver.removeListener(ShipTable.this);
}
});
// ウィンドウタイトルを設定
this.reloadTable();
this.shell.setText(this.getTitle());
}
private ShipFilterPanelConfigBean getPanelConfig() {
ShipFilterPanelConfigBean[] panelConfigs = AppConfig.get().getShipTablePanelVisibles();
if ((panelConfigs == null) || (panelConfigs.length < 4)) {
panelConfigs = new ShipFilterPanelConfigBean[4];
AppConfig.get().setShipTablePanelVisibles(panelConfigs);
}
if (panelConfigs[this.index] == null) {
panelConfigs[this.index] = new ShipFilterPanelConfigBean();
}
return panelConfigs[this.index];
}
private void updateSpecMenuState() {
this.switchdiff.setSelection(this.specdiff);
this.switchseparate.setSelection(this.specseparate);
if (this.switchdiff2 != null) {
this.switchdiff2.setSelection(this.specdiff);
this.switchseparate2.setSelection(this.specseparate);
}
}
private void switchSpecDiff(MenuItem source) {
this.specdiff = source.getSelection();
this.specseparate = false;
this.updateSpecMenuState();
this.reloadTable();
}
private void switchSpecSeparate(MenuItem source) {
this.specdiff = false;
this.specseparate = source.getSelection();
this.updateSpecMenuState();
this.reloadTable();
}
private void focusOnSearchBox() {
if ((this.filterCompo.getPanelVisible() == false) ||
(this.filterCompo.getEtcVisible() == false))
{
this.filterMenu.setPanelVisible(true, true);
this.filterCompo.setPanelVisible(true, true);
this.getShell().layout();
}
this.filterCompo.getSearchCombo().setFocus();
}
@Override
protected String getTitleMain() {
String name = AppConfig.get().getShipTableNames()[this.index];
if ((this.filter != null) &&
(this.filter.groupMode == 0) &&
(this.filter.group != null))
{
return name + " (" + this.filter.group.getName() + ")";
}
return name;
}
@Override
protected Point getSize() {
return SwtUtils.DPIAwareSize(new Point(600, 350));
}
@Override
protected String[] getTableHeader() {
return CreateReportLogic.getShipListHeader();
}
@Override
protected void updateTableBody() {
int specdisp = this.specseparate ? 2 : this.specdiff ? 1 : 0;
this.body = CreateReportLogic.getShipListBody(specdisp, this.filter);
}
@Override
protected TableItemCreator getTableItemCreator() {
return TableItemCreatorProxy.get(AppConstants.SHIPTABLE_PREFIX);
}
@Override
public String getWindowId() {
return this.getClass().getName() + ((this.index == 0) ? "" : String.valueOf(this.index));
}
/**
* フィルターを取得します。
* @return フィルター
*/
public ShipFilterDto getFilter() {
return this.filter;
}
public void windowTitleChanged() {
if (this.shell != null) {
this.shell.setText(this.getTitle());
}
}
private static Menu recreateCascadeMenu(MenuItem menuItem) {
Menu menu = menuItem.getMenu();
if (menu != null) {
menu.dispose();
}
menu = new Menu(menuItem);
menuItem.setMenu(menu);
return menu;
}
private List<ShipDto> getSelection() {
List<ShipDto> ships = new ArrayList<>();
TableItem[] tableItems = ShipTable.this.table.getSelection();
for (int i = 0; i < tableItems.length; i++) {
ShipDto dto = (ShipDto) tableItems[i].getData();
ships.add(dto);
}
return ships;
}
@Override
public void listChanged() {
this.filterMenu.updateGroupList();
List<ShipGroupBean> groups = ShipGroupConfig.get().getGroup();
Menu addGroupMenu = recreateCascadeMenu(this.addGroupCascade);
for (ShipGroupBean groupBean : groups) {
final MenuItem groupItem = new MenuItem(addGroupMenu, SWT.NONE);
groupItem.setText(groupBean.getName());
groupItem.setData(groupBean);
groupItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
List<ShipDto> ships = ShipTable.this.getSelection();
if (ships.size() > 0) {
List<String> name = new ArrayList<>();
for (ShipDto ship : ships) {
name.add(ship.getName());
}
MessageBox box = new MessageBox(ShipTable.this.shell, SWT.YES | SWT.NO
| SWT.ICON_QUESTION);
box.setText("選択した艦娘をグループに追加");
box.setMessage("「" + StringUtils.join(name, ",") + "」をグループに追加しますか?");
if (box.open() == SWT.YES) {
ShipGroupBean bean = (ShipGroupBean) e.widget.getData();
for (ShipDto ship : ships) {
bean.getShips().add(ship.getId());
}
ShipGroupObserver.groupShipChanged(bean);
}
}
}
});
}
Menu removeGroupMenu = recreateCascadeMenu(this.removeGroupCascade);
for (ShipGroupBean groupBean : groups) {
final MenuItem groupItem = new MenuItem(removeGroupMenu, SWT.NONE);
groupItem.setText(groupBean.getName());
groupItem.setData(groupBean);
groupItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
List<ShipDto> ships = ShipTable.this.getSelection();
if (ships.size() > 0) {
List<String> name = new ArrayList<>();
for (ShipDto ship : ships) {
name.add(ship.getName());
}
MessageBox box = new MessageBox(ShipTable.this.shell, SWT.YES | SWT.NO
| SWT.ICON_QUESTION);
box.setText("選択した艦娘をグループから除去");
box.setMessage("「" + StringUtils.join(name, ",") + "」をグループから除去しますか?");
if (box.open() == SWT.YES) {
ShipGroupBean bean = (ShipGroupBean) e.widget.getData();
for (ShipDto ship : ships) {
bean.getShips().remove(ship.getId());
}
ShipGroupObserver.groupShipChanged(bean);
}
}
}
});
}
}
@Override
public void save() {
if (this.filter != null) {
ShipFilterDto[] shipFilters = AppConfig.get().getShipFilters();
shipFilters[this.index] = this.filter;
AppConfig.get().setShipFilters(shipFilters);
ShipFilterPanelConfigBean panelConfig = this.getPanelConfig();
panelConfig.panelVisible = this.filterCompo.getPanelVisible();
panelConfig.etcVisible = this.filterCompo.getEtcVisible();
}
super.save();
}
@Override
public void groupNameChanged(ShipGroupBean group) {
if (this.filter.group == group) {
this.shell.setText(this.getTitle());
}
int idx = ShipGroupConfig.get().getGroup().indexOf(group);
if (idx != -1) {
this.filterMenu.updateGroupName(idx, group.getName());
this.addGroupCascade.getMenu().getItems()[idx].setText(group.getName());
this.removeGroupCascade.getMenu().getItems()[idx].setText(group.getName());
}
}
@Override
public void groupShipChanged(ShipGroupBean group) {
if (this.filter.group == group) {
this.reloadTable();
}
}
public FilterMenu getFilterMenu() {
return this.filterMenu;
}
public class FilterMenu {
private final MenuItem filterRoot;
private final Menu filterMenu;
private final MenuItem panelVisible;
private final MenuItem groupMenuItem;
private final MenuItem typeMenuItem;
private final MenuItem etcMenuItem;
private final int groupMenuPos;
private final List<MenuItem> groupItems = new ArrayList<MenuItem>();
public FilterMenu(Menu menubar) {
this.filterRoot = new MenuItem(menubar, SWT.CASCADE);
this.filterRoot.setText("フィルタ");
this.filterMenu = new Menu(this.filterRoot);
this.filterRoot.setMenu(this.filterMenu);
// フィルターメニュー
this.panelVisible = new MenuItem(this.filterMenu, SWT.CHECK);
this.panelVisible.setText("フィルターパネル(&D)\tCtrl+D");
this.panelVisible.setAccelerator(SWT.CTRL + 'D');
this.panelVisible.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FilterMenu.this.panelVisibleChanged();
}
});
// 検索(キーボードショートカットのため)
MenuItem searchMenu = new MenuItem(this.filterMenu, SWT.NONE);
searchMenu.setText("検索(&F)\tCtrl+F");
searchMenu.setAccelerator(SWT.CTRL + 'F');
searchMenu.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ShipTable.this.focusOnSearchBox();
}
});
// セパレータ
new MenuItem(this.filterMenu, SWT.SEPARATOR);
SelectionListener switchSelectionListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FilterMenu.this.switchMenuSelected(e);
}
};
this.groupMenuItem = new MenuItem(this.filterMenu, SWT.CHECK);
this.groupMenuItem.setText("グループ(&G)\tCtrl+G");
this.groupMenuItem.setAccelerator(SWT.CTRL + 'G');
this.groupMenuItem.addSelectionListener(switchSelectionListener);
this.typeMenuItem = new MenuItem(this.filterMenu, SWT.CHECK);
this.typeMenuItem.setText("艦種(&T)\tCtrl+T");
this.typeMenuItem.setAccelerator(SWT.CTRL + 'T');
this.typeMenuItem.addSelectionListener(switchSelectionListener);
// セパレータ
new MenuItem(this.filterMenu, SWT.SEPARATOR);
this.etcMenuItem = new MenuItem(this.filterMenu, SWT.CHECK);
this.etcMenuItem.setText("その他(&E)\tCtrl+E");
this.etcMenuItem.setAccelerator(SWT.CTRL + 'E');
this.etcMenuItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ShipTable.this.filterCompo.setPanelVisible(
FilterMenu.this.panelVisible.getSelection(),
FilterMenu.this.etcMenuItem.getSelection());
ShipTable.this.getShell().layout();
}
});
// セパレータ
new MenuItem(this.filterMenu, SWT.SEPARATOR);
this.groupMenuPos = this.filterMenu.getItemCount();
}
private void panelVisibleChanged() {
ShipTable.this.filterCompo.setPanelVisible(
this.panelVisible.getSelection(), this.etcMenuItem.getSelection());
ShipTable.this.getShell().layout();
}
private void switchMenuSelected(SelectionEvent e) {
MenuItem selectedItem = (MenuItem) e.widget;
int mode = !selectedItem.getSelection() ? 2 :
(selectedItem == this.groupMenuItem) ? 0 : 1;
ShipTable.this.filterCompo.setGroupMode(mode);
ShipTable.this.updateFilter(ShipTable.this.filterCompo.createFilter(), true);
ShipTable.this.getShell().layout();
}
public void setPanelVisible(boolean panelVisible, boolean etcVisible) {
this.panelVisible.setSelection(panelVisible);
this.etcMenuItem.setSelection(etcVisible);
}
private void setGroupMode(int mode) {
this.groupMenuItem.setSelection(mode == 0);
this.typeMenuItem.setSelection(mode == 1);
}
private void groupWidgetSelected(SelectionEvent e) {
MenuItem selectedItem = (MenuItem) e.widget;
boolean selection = selectedItem.getSelection();
ShipFilterDto filter = ShipTable.this.filter;
filter.groupMode = 0;
if (selection) {
ShipGroupBean bean = (ShipGroupBean) e.widget.getData();
filter.group = bean;
filter.groupId = bean.getId();
// これだけ残してあとはオフる
for (MenuItem item : this.groupItems) {
if (selectedItem != item) {
item.setSelection(false);
}
}
}
else {
filter.group = null;
filter.groupId = 0;
}
ShipTable.this.updateFilter(filter);
ShipTable.this.filterCompo.applyFilter(filter);
this.setGroupMode(0);
ShipTable.this.getShell().layout();
}
public void updateGroupList() {
List<ShipGroupBean> groups = ShipGroupConfig.get().getGroup();
for (MenuItem groupItem : this.groupItems) {
groupItem.dispose();
}
this.groupItems.clear();
if (groups.size() > 0) {
int insertPos = this.groupMenuPos;
for (ShipGroupBean groupBean : groups) {
final MenuItem groupItem = new MenuItem(this.filterMenu, SWT.CHECK, insertPos++);
groupItem.setText(groupBean.getName());
groupItem.setData(groupBean);
groupItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FilterMenu.this.groupWidgetSelected(e);
}
});
if (ShipTable.this.filter.group == groupBean) {
groupItem.setSelection(true);
}
this.groupItems.add(groupItem);
}
}
else {
final MenuItem groupItem = new MenuItem(this.filterMenu, SWT.NONE, this.groupMenuPos);
groupItem.setText("グループがありません");
groupItem.setEnabled(false);
this.groupItems.add(groupItem);
}
}
public void updateGroupName(int idx, String name) {
this.groupItems.get(idx).setText(name);
}
public void applyFilter(ShipFilterDto filter) {
// グループ
for (MenuItem item : this.groupItems) {
item.setSelection(false);
}
if ((filter.group != null) && (filter.groupMode == 0)) {
int idx = ShipGroupConfig.get().getGroup().indexOf(filter.group);
if (idx != -1) {
this.groupItems.get(idx).setSelection(true);
}
}
// モード
this.setGroupMode(filter.groupMode);
}
}
/**
* 更新する必要のあるデータ
*/
@Override
public void update(DataType type, Data data) {
if (ReportUtils.isShipUpdate(type)) {
this.needsUpdate = true;
}
}
}