1 package charactermanaj.ui;
\r
3 import static java.lang.Math.max;
\r
5 import java.awt.BorderLayout;
\r
6 import java.awt.Component;
\r
7 import java.awt.Container;
\r
8 import java.awt.GridBagConstraints;
\r
9 import java.awt.GridBagLayout;
\r
10 import java.awt.Insets;
\r
11 import java.awt.Toolkit;
\r
12 import java.awt.datatransfer.Clipboard;
\r
13 import java.awt.datatransfer.StringSelection;
\r
14 import java.awt.event.ActionEvent;
\r
15 import java.awt.event.ActionListener;
\r
16 import java.awt.event.KeyEvent;
\r
17 import java.awt.event.WindowAdapter;
\r
18 import java.awt.event.WindowEvent;
\r
19 import java.io.File;
\r
20 import java.io.IOException;
\r
21 import java.io.PrintWriter;
\r
22 import java.io.StringWriter;
\r
23 import java.net.URI;
\r
24 import java.util.Collections;
\r
25 import java.util.Properties;
\r
26 import java.util.logging.Level;
\r
27 import java.util.logging.Logger;
\r
29 import javax.swing.AbstractAction;
\r
30 import javax.swing.AbstractCellEditor;
\r
31 import javax.swing.ActionMap;
\r
32 import javax.swing.BorderFactory;
\r
33 import javax.swing.Box;
\r
34 import javax.swing.InputMap;
\r
35 import javax.swing.JButton;
\r
36 import javax.swing.JComponent;
\r
37 import javax.swing.JDialog;
\r
38 import javax.swing.JFrame;
\r
39 import javax.swing.JPanel;
\r
40 import javax.swing.JPopupMenu;
\r
41 import javax.swing.JRootPane;
\r
42 import javax.swing.JScrollPane;
\r
43 import javax.swing.JTable;
\r
44 import javax.swing.KeyStroke;
\r
45 import javax.swing.table.DefaultTableCellRenderer;
\r
46 import javax.swing.table.TableCellEditor;
\r
47 import javax.swing.table.TableCellRenderer;
\r
48 import javax.swing.table.TableColumn;
\r
49 import javax.swing.table.TableColumnModel;
\r
51 import charactermanaj.graphics.filters.ColorConvertParameter;
\r
52 import charactermanaj.graphics.io.ImageResource;
\r
53 import charactermanaj.graphics.io.PNGFileImageHeader;
\r
54 import charactermanaj.graphics.io.PNGFileImageHeaderReader;
\r
55 import charactermanaj.model.AppConfig;
\r
56 import charactermanaj.model.Layer;
\r
57 import charactermanaj.model.PartsIdentifier;
\r
58 import charactermanaj.model.PartsSet;
\r
59 import charactermanaj.model.PartsSpecResolver;
\r
60 import charactermanaj.model.io.PartsImageCollectionParser;
\r
61 import charactermanaj.model.io.PartsImageCollectionParser.PartsImageCollectionHandler;
\r
62 import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;
\r
63 import charactermanaj.util.DesktopUtilities;
\r
64 import charactermanaj.util.ErrorMessageHelper;
\r
65 import charactermanaj.util.LocalizedResourcePropertyLoader;
\r
71 public class InformationDialog extends JDialog {
\r
73 private static final long serialVersionUID = 1L;
\r
75 private static final Logger logger = Logger.getLogger(InformationDialog.class.getName());
\r
77 protected static final String STRINGS_RESOURCE = "languages/informationdialog";
\r
79 private JTable informationTable;
\r
81 private InformationTableModel informationTableModel;
\r
83 private boolean modeOpen;
\r
85 public InformationDialog(JFrame parent, PartsSpecResolver partsSpecResolver, PartsSet partsSet) {
\r
86 super(parent, true);
\r
88 AppConfig appConfig = AppConfig.getInstance();
\r
89 modeOpen = appConfig.isInformationDialogOpenMethod();
\r
91 if (partsSpecResolver == null) {
\r
92 throw new IllegalArgumentException("partsSpecResolver is null");
\r
94 if (partsSet == null) {
\r
95 throw new IllegalArgumentException("partsSet is null");
\r
98 setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
\r
99 addWindowListener(new WindowAdapter() {
\r
101 public void windowClosing(WindowEvent e) {
\r
106 final Properties strings = LocalizedResourcePropertyLoader
\r
107 .getCachedInstance().getLocalizedProperties(STRINGS_RESOURCE);
\r
109 setTitle(strings.getProperty("title"));
\r
111 informationTableModel = new InformationTableModel();
\r
113 final PNGFileImageHeaderReader pngHeaderReader = PNGFileImageHeaderReader.getInstance();
\r
115 PartsImageCollectionParser parser = new PartsImageCollectionParser(partsSpecResolver);
\r
116 parser.parse(partsSet, new PartsImageCollectionHandler() {
\r
117 public void detectImageSource(PartsIdentifier partsIdentifier, Layer layer,
\r
118 final ImageResource imageResource, ColorConvertParameter param) {
\r
120 AbstractAction act = new AbstractAction(strings.getProperty(modeOpen ? "btn.edit.open" : "btn.edit.edit")) {
\r
121 private static final long serialVersionUID = 1L;
\r
122 public void actionPerformed(ActionEvent e) {
\r
123 onOpen(imageResource);
\r
127 URI uri = imageResource.getURI();
\r
128 if (uri != null && "file".equals(uri.getScheme()) && DesktopUtilities.isSupported()) {
\r
129 act.setEnabled(true);
\r
131 act.setEnabled(false);
\r
134 PNGFileImageHeader pngHeader;
\r
136 pngHeader = pngHeaderReader.readHeader(uri);
\r
137 } catch (IOException ex) {
\r
138 logger.log(Level.WARNING, "PNG Header loading error.: " + uri, ex);
\r
142 InformationModel information = new InformationModel(partsIdentifier, layer, imageResource, param, pngHeader, act);
\r
143 informationTableModel.addRow(information);
\r
146 informationTableModel.sort();
\r
148 informationTable = new JTable(informationTableModel) {
\r
149 private static final long serialVersionUID = 1L;
\r
151 public Component prepareRenderer(final TableCellRenderer renderer,
\r
152 final int row, final int column) {
\r
153 final Component prepareRenderer = super.prepareRenderer(renderer, row, column);
\r
154 final TableColumn tableColumn = getColumnModel().getColumn(column);
\r
155 int preferredWidth = max(prepareRenderer
\r
156 .getPreferredSize().width, tableColumn
\r
157 .getPreferredWidth()); // セルかヘッダのどちらか幅の大きいほう
\r
158 if (tableColumn.getPreferredWidth() != preferredWidth) {
\r
159 tableColumn.setPreferredWidth(preferredWidth);
\r
161 return prepareRenderer;
\r
164 informationTableModel.adjustColumnModel(informationTable.getColumnModel());
\r
165 informationTable.setShowGrid(true);
\r
166 informationTable.setGridColor(appConfig.getGridColor());
\r
167 informationTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
\r
168 informationTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
\r
169 informationTable.setRowHeight(informationTable.getRowHeight() + 4);
\r
171 informationTable.setDefaultRenderer(JButton.class, new ButtonCellRender());
\r
172 informationTable.setDefaultEditor(JButton.class, new ButtonCellEditor());
\r
174 // セルデータの幅にあわせる(事前に)
\r
175 for (int row = 0; row < informationTable.getRowCount(); row++) {
\r
176 for (int col = 0; col < informationTable.getColumnCount(); col++) {
\r
177 TableCellRenderer renderer = informationTable.getCellRenderer(row, col);
\r
178 informationTable.prepareRenderer(renderer, row, col);
\r
182 final JPopupMenu popupMenu = new JPopupMenu();
\r
183 popupMenu.add(new AbstractAction(strings.getProperty("popupmenu.copyPath")) {
\r
184 private static final long serialVersionUID = 1L;
\r
185 public void actionPerformed(ActionEvent e) {
\r
190 informationTable.setComponentPopupMenu(popupMenu);
\r
192 Container contentPane = getContentPane();
\r
193 contentPane.setLayout(new BorderLayout());
\r
194 JScrollPane informationTableSP = new JScrollPane(informationTable);
\r
195 JPanel informationTableSPPabel = new JPanel(new BorderLayout());
\r
196 informationTableSPPabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
\r
197 informationTableSPPabel.add(informationTableSP, BorderLayout.CENTER);
\r
198 contentPane.add(informationTableSPPabel, BorderLayout.CENTER);
\r
200 AbstractAction actClose = new AbstractAction(strings.getProperty("btnClose")) {
\r
201 private static final long serialVersionUID = 1L;
\r
202 public void actionPerformed(ActionEvent e) {
\r
207 JPanel btnPanel = new JPanel();
\r
208 btnPanel.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 45));
\r
209 GridBagLayout btnPanelLayout = new GridBagLayout();
\r
210 btnPanel.setLayout(btnPanelLayout);
\r
212 GridBagConstraints gbc = new GridBagConstraints();
\r
215 gbc.gridheight = 1;
\r
217 gbc.anchor = GridBagConstraints.EAST;
\r
218 gbc.fill = GridBagConstraints.BOTH;
\r
219 gbc.insets = new Insets(3, 3, 3, 3);
\r
224 btnPanel.add(Box.createHorizontalGlue(), gbc);
\r
230 JButton btnClose = new JButton(actClose);
\r
231 btnPanel.add(btnClose, gbc);
\r
233 contentPane.add(btnPanel, BorderLayout.SOUTH);
\r
235 Toolkit tk = Toolkit.getDefaultToolkit();
\r
236 JRootPane rootPane = getRootPane();
\r
237 rootPane.setDefaultButton(btnClose);
\r
239 InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
\r
240 ActionMap am = rootPane.getActionMap();
\r
241 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), "closeInformationDialog");
\r
242 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "closeInformationDialog");
\r
243 am.put("closeInformationDialog", actClose);
\r
246 setLocationRelativeTo(parent);
\r
249 protected void onClose() {
\r
253 protected void onCopyFilePath() {
\r
254 StringWriter sw = new StringWriter();
\r
255 PrintWriter pw = new PrintWriter(sw);
\r
256 for (int selRow : informationTable.getSelectedRows()) {
\r
257 InformationModel information = informationTableModel.getRow(selRow);
\r
258 pw.println(information.getImageResourceName());
\r
261 Toolkit tk = Toolkit.getDefaultToolkit();
\r
263 String text = sw.toString();
\r
264 if (text.length() == 0) {
\r
269 StringSelection textSelection = new StringSelection(sw.toString());
\r
271 Clipboard cb = tk.getSystemClipboard();
\r
272 cb.setContents(textSelection, null);
\r
275 protected void onOpen(ImageResource imageResource) {
\r
277 URI uri = imageResource.getURI();
\r
278 if (uri != null && "file".equals(uri.getScheme())) {
\r
279 File file = new File(uri);
\r
280 DesktopUtilities.open(file);
\r
283 } catch (Exception ex) {
\r
284 ErrorMessageHelper.showErrorDialog(this, ex);
\r
289 class InformationTableModel extends AbstractTableModelWithComboBoxModel<InformationModel> {
\r
291 private static final long serialVersionUID = 1L;
\r
293 private static final String[] columnNames;
\r
295 private static final int[] columnWidths;
\r
297 public static final int COLUMN_BUTTON;
\r
300 final Properties strings = LocalizedResourcePropertyLoader
\r
301 .getCachedInstance().getLocalizedProperties(InformationDialog.STRINGS_RESOURCE);
\r
303 columnNames = new String[] {
\r
304 strings.getProperty("column.partsName"),
\r
305 strings.getProperty("column.categoryName"),
\r
306 strings.getProperty("column.layerName"),
\r
307 strings.getProperty("column.layerOrder"),
\r
308 strings.getProperty("column.imagesize"),
\r
309 strings.getProperty("column.colortype"),
\r
310 strings.getProperty("column.imageName"),
\r
311 strings.getProperty("column.editbtn"),
\r
314 columnWidths = new int[] {
\r
315 Integer.parseInt(strings.getProperty("column.partsName.width")),
\r
316 Integer.parseInt(strings.getProperty("column.categoryName.width")),
\r
317 Integer.parseInt(strings.getProperty("column.layerName.width")),
\r
318 Integer.parseInt(strings.getProperty("column.layerOrder.width")),
\r
319 Integer.parseInt(strings.getProperty("column.layerOrder.imagesize.width")),
\r
320 Integer.parseInt(strings.getProperty("column.layerOrder.colortype.width")),
\r
321 Integer.parseInt(strings.getProperty("column.imageName.width")),
\r
322 Integer.parseInt(strings.getProperty("column.editbtn.width")),
\r
326 public void adjustColumnModel(TableColumnModel columnModel) {
\r
327 for (int idx = 0; idx < columnWidths.length; idx++) {
\r
328 columnModel.getColumn(idx).setPreferredWidth(columnWidths[idx]);
\r
332 public int getColumnCount() {
\r
333 return columnNames.length;
\r
337 public String getColumnName(int column) {
\r
338 return columnNames[column];
\r
342 public Class<?> getColumnClass(int columnIndex) {
\r
343 switch (columnIndex) {
\r
345 return String.class;
\r
347 return String.class;
\r
349 return String.class;
\r
351 return Integer.class;
\r
353 return String.class;
\r
355 return String.class;
\r
357 return String.class;
\r
359 return JButton.class;
\r
361 return String.class;
\r
364 public Object getValueAt(int rowIndex, int columnIndex) {
\r
365 InformationModel information = getRow(rowIndex);
\r
366 switch (columnIndex) {
\r
368 return information.getPartsName();
\r
370 return information.getCategoryName();
\r
372 return information.getLayerName();
\r
374 return information.getLayerOrder();
\r
376 return information.getImageSizeStr();
\r
378 return information.getColorTypeStr();
\r
380 return information.getImageResourceName();
\r
382 return information.getButton();
\r
387 public void sort() {
\r
388 Collections.sort(elements);
\r
389 fireTableDataChanged();
\r
393 public boolean isCellEditable(int rowIndex, int columnIndex) {
\r
394 InformationModel information = getRow(rowIndex);
\r
395 if (columnIndex == COLUMN_BUTTON) {
\r
396 return information.getButton().isEnabled();
\r
403 class InformationModel implements Comparable<InformationModel> {
\r
405 private PartsIdentifier partsIdentifier;
\r
407 private Layer layer;
\r
409 private ImageResource imageResource;
\r
411 private JButton btnOpen;
\r
413 private PNGFileImageHeader pngHeader;
\r
415 public InformationModel(PartsIdentifier partsIdentifier, Layer layer,
\r
416 ImageResource imageResource,
\r
417 ColorConvertParameter colorConvertParameter,
\r
418 PNGFileImageHeader pngHeader,
\r
419 AbstractAction actOpen) {
\r
420 this.partsIdentifier = partsIdentifier;
\r
421 this.layer = layer;
\r
422 this.imageResource = imageResource;
\r
423 this.pngHeader = pngHeader;
\r
424 this.btnOpen = new JButton(actOpen) {
\r
425 private static final long serialVersionUID = 1L;
\r
427 public String toString() {
\r
428 // JTableをクリップボードにコピーしたときに設定されるカラムの文字列表現
\r
435 public int hashCode() {
\r
436 return partsIdentifier.hashCode();
\r
440 public boolean equals(Object obj) {
\r
444 if (obj != null && obj instanceof InformationModel) {
\r
445 InformationModel o = (InformationModel) obj;
\r
446 return partsIdentifier.equals(o.partsIdentifier)
\r
447 && layer.equals(o.layer);
\r
452 public int compareTo(InformationModel o) {
\r
453 int ret = partsIdentifier.compareTo(o.partsIdentifier);
\r
455 ret = layer.compareTo(o.layer);
\r
458 ret = imageResource.compareTo(o.imageResource);
\r
463 public String getPartsName() {
\r
464 return this.partsIdentifier.getLocalizedPartsName();
\r
467 public String getCategoryName() {
\r
468 return this.partsIdentifier.getPartsCategory().getLocalizedCategoryName();
\r
471 public String getLayerName() {
\r
472 return this.layer.getLocalizedName();
\r
475 public int getLayerOrder() {
\r
476 return this.layer.getOrder();
\r
479 public String getImageResourceName() {
\r
480 return this.imageResource.getFullName();
\r
483 public JButton getButton() {
\r
487 public String getImageSizeStr() {
\r
488 if (pngHeader == null) {
\r
491 return pngHeader.getWidth() + "x" + pngHeader.getHeight();
\r
494 public String getColorTypeStr() {
\r
495 if (pngHeader == null) {
\r
499 StringBuilder buf = new StringBuilder();
\r
501 int colorType = pngHeader.getColorType();
\r
502 if ((colorType & 0x01) != 0) {
\r
503 buf.append("Indexed ");
\r
505 if ((colorType & 0x02) != 0) {
\r
506 buf.append("Color ");
\r
509 buf.append("Greyscale ");
\r
512 if (colorType == 6 || pngHeader.hasTransparencyInformation()) {
\r
513 // 6:TrueColor または アルファ情報がある場合のみアルファ有りとする.
\r
514 buf.append("Alpha ");
\r
517 buf.append(pngHeader.getBitDepth() + "bit");
\r
519 return buf.toString().trim();
\r
527 class ButtonCellRender extends DefaultTableCellRenderer {
\r
529 private static final long serialVersionUID = 1L;
\r
532 public Component getTableCellRendererComponent(JTable table, Object value,
\r
533 boolean isSelected, boolean hasFocus, int row, int column) {
\r
534 super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
\r
535 return (JButton) value;
\r
543 class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {
\r
545 private static final long serialVersionUID = 1L;
\r
547 public Component getTableCellEditorComponent(final JTable table, final Object value,
\r
548 final boolean isSelected, final int row, final int column) {
\r
549 final JButton orgBtn = (JButton) value;
\r
550 final JButton btn = new JButton(new AbstractAction(orgBtn.getText()) {
\r
551 private static final long serialVersionUID = 1L;
\r
552 public void actionPerformed(ActionEvent e) {
\r
553 fireEditingCanceled();
\r
554 for (ActionListener listener : orgBtn.getActionListeners()) {
\r
555 listener.actionPerformed(e);
\r
562 public Object getCellEditorValue() {
\r