package logbook.gui; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; import logbook.constants.AppConstants; import logbook.data.Data; import logbook.data.DataType; import logbook.dto.BattleExDto; import logbook.dto.BattleResultDto; import logbook.gui.logic.BattleHtmlGenerator; import logbook.gui.logic.CreateReportLogic; import logbook.gui.logic.GuiUpdator; import logbook.gui.logic.TableItemCreator; import logbook.gui.logic.TableRowHeader; import logbook.internal.BattleResultFilter; import logbook.internal.BattleResultServer; import logbook.internal.LoggerHolder; import logbook.internal.TimeSpanKind; import logbook.scripting.TableItemCreatorProxy; import logbook.util.SwtUtils; import org.apache.commons.io.FileUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; 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.widgets.Event; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; /** * ドロップ報告書 * */ public final class DropReportTable extends AbstractTableDialog { /** ロガー */ private static final LoggerHolder LOG = new LoggerHolder(DropReportTable.class); private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HHmmss.SSS"); private BattleResultFilter filter = new BattleResultFilter(); private BattleFilterDialog battleFilterDialog; private final BattleDetailDialog detailDialog; /** * @param parent */ public DropReportTable(Shell parent, MenuItem menuItem) { super(parent, menuItem); this.detailDialog = new BattleDetailDialog(parent); this.filter.printPractice = false; this.filter.timeSpan = TimeSpanKind.LAST_24HOURS; } public void updateFilter(BattleResultFilter filter) { this.filter = filter; this.reloadTable(); } @Override protected void createContents() { final MenuItem reloadDB = new MenuItem(this.opemenu, SWT.NONE); reloadDB.setText("データベースを再読み込み"); reloadDB.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { MessageBox box = new MessageBox(DropReportTable.this.shell, SWT.YES | SWT.NO | SWT.ICON_QUESTION); box.setText("データベース再読み込み"); box.setMessage("件数によっては時間がかかることがあります。よろしいですか?"); if (box.open() == SWT.YES) { BattleResultServer.get().reloadFiles(); DropReportTable.this.reloadTable(); } } }); this.table.addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { int selected = DropReportTable.this.table.getSelectionIndex(); if (selected != -1) { BattleResultDto result = DropReportTable.this.getItemFromIndex(selected); DropReportTable.this.detailDialog.open(); DropReportTable.this.detailDialog.setBattle( DropReportTable.this.getHTMLOfItem(result, false), DropReportTable.this.getBattleTitle(result)); } } }); SelectionListener filterListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (DropReportTable.this.battleFilterDialog == null) DropReportTable.this.battleFilterDialog = new BattleFilterDialog(DropReportTable.this); DropReportTable.this.battleFilterDialog.open(); } }; if (!this.isNoMenubar()) { // フィルターメニュー final MenuItem filter = new MenuItem(this.menubar, SWT.PUSH); filter.setText("フィルター"); filter.setAccelerator(SWT.CTRL + 'F'); filter.addSelectionListener(filterListener); } // セパレータ new MenuItem(this.tablemenu, SWT.SEPARATOR); // 右クリックメニューに追加する final MenuItem filtertable = new MenuItem(this.tablemenu, SWT.NONE); filtertable.setText("フィルター(&F)\tCtrl+F"); filtertable.addSelectionListener(filterListener); // 保存メニュー final MenuItem save = new MenuItem(this.tablemenu, SWT.NONE); save.setText("選択したログを保存する"); save.addSelectionListener(new SaveAdapter()); // データの更新を受け取る final Runnable listener = new GuiUpdator(new Runnable() { @Override public void run() { DropReportTable.this.reloadTable(); } }); BattleResultServer.addListener(listener); this.shell.addListener(SWT.Dispose, new Listener() { @Override public void handleEvent(Event event) { BattleResultServer.removeListener(listener); } }); } private BattleResultDto getItemFromIndex(int index) { TableRowHeader rowHeader = (TableRowHeader) DropReportTable.this.body.get(index)[0]; return (BattleResultDto) rowHeader.get(); } private String getBattleTitle(BattleResultDto item) { if (item.isPractice()) { return "演習報告: " + item.getEnemyName(); } return "会敵報告: " + item.getMapCell().detailedString(); } private String getOutputFileName(BattleResultDto item) { String rank = item.getRank().toString(); if (item.isPractice()) { return dateFormat.format(item.getBattleDate()) + "演習" + rank; } else { int[] map = item.getMapCell().getMap(); return dateFormat.format(item.getBattleDate()) + " " + map[0] + "-" + map[1] + "-" + map[2] + " " + rank; } } private String getHTMLOfItem(BattleResultDto item, boolean forFile) { String title = this.getBattleTitle(item); BattleExDto detail = BattleResultServer.get().getBattleDetail(item); try { BattleHtmlGenerator gen = new BattleHtmlGenerator(); return gen.generateHTML(title, item, detail, forFile); } catch (IOException e) { LOG.get().warn("会敵報告作成に失敗: CSSファイル読み込みに失敗しました", e); } catch (Exception e) { ApplicationMain.main.printMessage("会敵報告作成に失敗しました"); LOG.get().warn("会敵報告作成に失敗", e); } return null; } private void writeToFile(BattleResultDto item, File file) { Shell shell = this.getShell(); try { FileUtils.writeStringToFile(file, this.getHTMLOfItem(item, true), "UTF-8"); } catch (IOException ex) { MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR); messageBox.setText("書き込めませんでした"); messageBox.setMessage(ex.toString()); messageBox.open(); } } private void writeToZipFile(List<BattleResultDto> items, File file) { Shell shell = this.getShell(); ZipOutputStream zipOutStream = null; List<String> failedList = new ArrayList<String>(); try { zipOutStream = new ZipOutputStream( new BufferedOutputStream(new FileOutputStream(file))); for (BattleResultDto item : items) { String fileName = this.getOutputFileName(item) + ".html"; String html = this.getHTMLOfItem(item, true); if (html != null) { final ZipEntry entry = new ZipEntry(fileName); try { zipOutStream.putNextEntry(entry); zipOutStream.write(html.getBytes(Charset.forName("UTF-8"))); zipOutStream.closeEntry(); } catch (ZipException e) { failedList.add(fileName); } } else { failedList.add(fileName); } } zipOutStream.finish(); zipOutStream.close(); if (failedList.size() > 0) { StringBuilder sb = new StringBuilder("以下のファイルを書き込めませんでした\r\n"); for (String failedFile : failedList) { sb.append(failedFile).append("\r\n"); } MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR); messageBox.setText("一部でエラーが発生しました"); messageBox.setMessage(sb.toString()); messageBox.open(); } } catch (IOException ex) { MessageBox messageBox = new MessageBox(shell, SWT.ICON_ERROR); messageBox.setText("書き込めませんでした"); messageBox.setMessage(ex.toString()); messageBox.open(); } finally { if (zipOutStream != null) { try { zipOutStream.close(); } catch (IOException e) { // } } } } private List<BattleResultDto> getSelectedItemList() { int[] selectedIndices = this.table.getSelectionIndices(); List<BattleResultDto> ret = new ArrayList<BattleResultDto>(); for (int index : selectedIndices) { ret.add(this.getItemFromIndex(index)); } return ret; } public BattleResultFilter getFilter() { return this.filter; } @Override protected String getTitleMain() { return "ドロップ報告書"; } @Override protected Point getSize() { return SwtUtils.DPIAwareSize(new Point(600, 350)); } @Override protected String[] getTableHeader() { return CreateReportLogic.getBattleResultHeader(); } @Override protected void updateTableBody() { this.body = CreateReportLogic.getBattleResultBody(this.filter); } @Override protected TableItemCreator getTableItemCreator() { //return CreateReportLogic.DEFAULT_TABLE_ITEM_CREATOR; return TableItemCreatorProxy.get(AppConstants.DROPTABLE_PREFIX); } /** * HTMLファイルとして保存のリスナー * */ private class SaveAdapter extends SelectionAdapter { @Override public void widgetSelected(SelectionEvent e) { if (DropReportTable.this.table.getSelectionIndex() == -1) { // 選択されていないときは返る return; } List<BattleResultDto> selectedItems = DropReportTable.this.getSelectedItemList(); Shell shell = DropReportTable.this.getShell(); FileDialog dialog = new FileDialog(shell, SWT.SAVE); String fileName = DropReportTable.this.getOutputFileName(selectedItems.get(0)); if (selectedItems.size() > 1) { // 2つ以上選択されているときはzip出力 dialog.setFileName(fileName + ".zip"); dialog.setFilterExtensions(new String[] { "*.zip" }); } else { dialog.setFileName(fileName + ".html"); dialog.setFilterExtensions(new String[] { "*.html" }); } String filename = dialog.open(); if (filename != null) { File file = new File(filename); if (file.exists()) { MessageBox messageBox = new MessageBox(shell, SWT.YES | SWT.NO); messageBox.setText("確認"); messageBox.setMessage("指定されたファイルは存在します。\n上書きしますか?"); if (messageBox.open() == SWT.NO) { return; } } if (selectedItems.size() > 1) { DropReportTable.this.writeToZipFile(selectedItems, file); } else { DropReportTable.this.writeToFile(selectedItems.get(0), file); } } } } /** * 更新する必要のあるデータ */ @Override public void update(DataType type, Data data) { // BattleResultServerから直接更新を受け取るので何もしない } }