OSDN Git Service

キャラクターデータの独自独自テンプレートの作成機能の追加
[charactermanaj/CharacterManaJ.git] / src / charactermanaj / ui / InformationDialog.java
1 package charactermanaj.ui;\r
2 \r
3 import static java.lang.Math.max;\r
4 \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
28 \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
50 \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
66 \r
67 /**\r
68  * 情報ダイアログを開く\r
69  * @author seraphy\r
70  */\r
71 public class InformationDialog extends JDialog {\r
72 \r
73         private static final long serialVersionUID = 1L;\r
74         \r
75         private static final Logger logger = Logger.getLogger(InformationDialog.class.getName());\r
76         \r
77         protected static final String STRINGS_RESOURCE = "languages/informationdialog";\r
78 \r
79         private JTable informationTable;\r
80         \r
81         private InformationTableModel informationTableModel;\r
82         \r
83         private boolean modeOpen;\r
84 \r
85         public InformationDialog(JFrame parent, PartsSpecResolver partsSpecResolver, PartsSet partsSet) {\r
86                 super(parent, true);\r
87                 \r
88                 AppConfig appConfig = AppConfig.getInstance();\r
89                 modeOpen = appConfig.isInformationDialogOpenMethod();\r
90                 \r
91                 if (partsSpecResolver == null) {\r
92                         throw new IllegalArgumentException("partsSpecResolver is null");\r
93                 }\r
94                 if (partsSet == null) {\r
95                         throw new IllegalArgumentException("partsSet is null");\r
96                 }\r
97                 \r
98                 setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);\r
99                 addWindowListener(new WindowAdapter() {\r
100                         @Override\r
101                         public void windowClosing(WindowEvent e) {\r
102                                 onClose();\r
103                         }\r
104                 });\r
105                 \r
106                 final Properties strings = LocalizedResourcePropertyLoader\r
107                                 .getCachedInstance().getLocalizedProperties(STRINGS_RESOURCE);\r
108                 \r
109                 setTitle(strings.getProperty("title"));\r
110                 \r
111                 informationTableModel = new InformationTableModel();\r
112                 \r
113                 final PNGFileImageHeaderReader pngHeaderReader = PNGFileImageHeaderReader.getInstance();\r
114                 \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
119                                 \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
124                                         }\r
125                                 };\r
126 \r
127                                 URI uri = imageResource.getURI();\r
128                                 if (uri != null && "file".equals(uri.getScheme()) && DesktopUtilities.isSupported()) {\r
129                                         act.setEnabled(true);\r
130                                 } else {\r
131                                         act.setEnabled(false);\r
132                                 }\r
133                                 \r
134                                 PNGFileImageHeader pngHeader;\r
135                                 try {\r
136                                         pngHeader = pngHeaderReader.readHeader(uri);\r
137                                 } catch (IOException ex) {\r
138                                         logger.log(Level.WARNING, "PNG Header loading error.: " + uri, ex);\r
139                                         pngHeader = null;\r
140                                 }\r
141 \r
142                                 InformationModel information = new InformationModel(partsIdentifier, layer, imageResource, param, pngHeader, act);\r
143                                 informationTableModel.addRow(information);\r
144                         }\r
145                 });\r
146                 informationTableModel.sort();\r
147                 \r
148                 informationTable = new JTable(informationTableModel) {\r
149                         private static final long serialVersionUID = 1L;\r
150                         // セルの幅を大きいものにあわせる\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
160                                 }\r
161                                 return prepareRenderer;\r
162                         }\r
163                 };\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
170                 \r
171                 informationTable.setDefaultRenderer(JButton.class, new ButtonCellRender());\r
172                 informationTable.setDefaultEditor(JButton.class, new ButtonCellEditor());\r
173                 \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
179                         }\r
180                 }\r
181                 \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
186                                 onCopyFilePath();\r
187                         }\r
188                 });\r
189                 \r
190                 informationTable.setComponentPopupMenu(popupMenu);\r
191                 \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
199 \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
203                                 onClose();\r
204                         }\r
205                 };\r
206                 \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
211                 \r
212                 GridBagConstraints gbc = new GridBagConstraints();\r
213                 gbc.gridx = 0;\r
214                 gbc.gridy = 0;\r
215                 gbc.gridheight = 1;\r
216                 gbc.gridwidth = 1;\r
217                 gbc.anchor = GridBagConstraints.EAST;\r
218                 gbc.fill = GridBagConstraints.BOTH;\r
219                 gbc.insets = new Insets(3, 3, 3, 3);\r
220                 gbc.ipadx = 0;\r
221                 gbc.ipady = 0;\r
222                 gbc.weightx = 1.;\r
223                 gbc.weighty = 0.;\r
224                 btnPanel.add(Box.createHorizontalGlue(), gbc);\r
225                 \r
226                 gbc.gridx = 1;\r
227                 gbc.gridy = 0;\r
228                 gbc.weightx = 0.;\r
229                 gbc.weighty = 0.;\r
230                 JButton btnClose = new JButton(actClose);\r
231                 btnPanel.add(btnClose, gbc);\r
232                 \r
233                 contentPane.add(btnPanel, BorderLayout.SOUTH);\r
234                 \r
235                 Toolkit tk = Toolkit.getDefaultToolkit();\r
236                 JRootPane rootPane = getRootPane();\r
237                 rootPane.setDefaultButton(btnClose);\r
238                 \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
244                 \r
245                 pack();\r
246                 setLocationRelativeTo(parent);\r
247         }\r
248         \r
249         protected void onClose() {\r
250                 dispose();\r
251         }\r
252         \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
259                 }\r
260 \r
261                 Toolkit tk = Toolkit.getDefaultToolkit();\r
262 \r
263                 String text = sw.toString();\r
264                 if (text.length() == 0) {\r
265                         tk.beep();\r
266                         return;\r
267                 }\r
268 \r
269                 StringSelection textSelection = new StringSelection(sw.toString());\r
270 \r
271                 Clipboard cb = tk.getSystemClipboard();\r
272                 cb.setContents(textSelection, null);\r
273         }\r
274         \r
275         protected void onOpen(ImageResource imageResource) {\r
276                 try {\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
281                         }\r
282 \r
283                 } catch (Exception ex) {\r
284                         ErrorMessageHelper.showErrorDialog(this, ex);\r
285                 }\r
286         }\r
287 }\r
288 \r
289 class InformationTableModel extends AbstractTableModelWithComboBoxModel<InformationModel> {\r
290         \r
291         private static final long serialVersionUID = 1L;\r
292 \r
293         private static final String[] columnNames;\r
294         \r
295         private static final int[] columnWidths;\r
296         \r
297         public static final int COLUMN_BUTTON;\r
298         \r
299         static {\r
300                 final Properties strings = LocalizedResourcePropertyLoader\r
301                                 .getCachedInstance().getLocalizedProperties(InformationDialog.STRINGS_RESOURCE);\r
302 \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
312                 };\r
313                 COLUMN_BUTTON = 7;\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
323                 };\r
324         }\r
325         \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
329                 }\r
330         }\r
331 \r
332         public int getColumnCount() {\r
333                 return columnNames.length;\r
334         }\r
335         \r
336         @Override\r
337         public String getColumnName(int column) {\r
338                 return columnNames[column];\r
339         }\r
340         \r
341         @Override\r
342         public Class<?> getColumnClass(int columnIndex) {\r
343                 switch (columnIndex) {\r
344                 case 0:\r
345                         return String.class;\r
346                 case 1:\r
347                         return String.class;\r
348                 case 2:\r
349                         return String.class;\r
350                 case 3:\r
351                         return Integer.class;\r
352                 case 4:\r
353                         return String.class;\r
354                 case 5:\r
355                         return String.class;\r
356                 case 6:\r
357                         return String.class;\r
358                 case 7:\r
359                         return JButton.class;\r
360                 }\r
361                 return String.class;\r
362         }\r
363         \r
364         public Object getValueAt(int rowIndex, int columnIndex) {\r
365                 InformationModel information = getRow(rowIndex);\r
366                 switch (columnIndex) {\r
367                 case 0:\r
368                         return information.getPartsName();\r
369                 case 1:\r
370                         return information.getCategoryName();\r
371                 case 2:\r
372                         return information.getLayerName();\r
373                 case 3:\r
374                         return information.getLayerOrder();\r
375                 case 4:\r
376                         return information.getImageSizeStr();\r
377                 case 5:\r
378                         return information.getColorTypeStr();\r
379                 case 6:\r
380                         return information.getImageResourceName();\r
381                 case 7:\r
382                         return information.getButton();\r
383                 }\r
384                 return "";\r
385         }\r
386         \r
387         public void sort() {\r
388                 Collections.sort(elements);\r
389                 fireTableDataChanged();\r
390         }\r
391         \r
392         @Override\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
397                 }\r
398                 return false;\r
399         }\r
400         \r
401 }\r
402 \r
403 class InformationModel implements Comparable<InformationModel> {\r
404         \r
405         private PartsIdentifier partsIdentifier;\r
406 \r
407         private Layer layer;\r
408         \r
409         private ImageResource imageResource;\r
410         \r
411         private JButton btnOpen;\r
412         \r
413         private PNGFileImageHeader pngHeader;\r
414         \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
426                         @Override\r
427                         public String toString() {\r
428                                 // JTableをクリップボードにコピーしたときに設定されるカラムの文字列表現\r
429                                 return "open";\r
430                         }\r
431                 };\r
432         }\r
433         \r
434         @Override\r
435         public int hashCode() {\r
436                 return partsIdentifier.hashCode();\r
437         }\r
438         \r
439         @Override\r
440         public boolean equals(Object obj) {\r
441                 if (obj == this) {\r
442                         return true;\r
443                 }\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
448                 }\r
449                 return false;\r
450         }\r
451         \r
452         public int compareTo(InformationModel o) {\r
453                 int ret = partsIdentifier.compareTo(o.partsIdentifier);\r
454                 if (ret == 0) {\r
455                         ret = layer.compareTo(o.layer);\r
456                 }\r
457                 if (ret == 0) {\r
458                         ret = imageResource.compareTo(o.imageResource);\r
459                 }\r
460                 return ret;\r
461         }\r
462 \r
463         public String getPartsName() {\r
464                 return this.partsIdentifier.getLocalizedPartsName();\r
465         }\r
466         \r
467         public String getCategoryName() {\r
468                 return this.partsIdentifier.getPartsCategory().getLocalizedCategoryName();\r
469         }\r
470         \r
471         public String getLayerName() {\r
472                 return this.layer.getLocalizedName();\r
473         }\r
474         \r
475         public int getLayerOrder() {\r
476                 return this.layer.getOrder();\r
477         }\r
478         \r
479         public String getImageResourceName() {\r
480                 return this.imageResource.getFullName();\r
481         }\r
482         \r
483         public JButton getButton() {\r
484                 return btnOpen;\r
485         }\r
486         \r
487         public String getImageSizeStr() {\r
488                 if (pngHeader == null) {\r
489                         return "INVALID";\r
490                 }\r
491                 return pngHeader.getWidth() + "x" + pngHeader.getHeight();\r
492         }\r
493         \r
494         public String getColorTypeStr() {\r
495                 if (pngHeader == null) {\r
496                         return "INVALID";\r
497                 }\r
498 \r
499                 StringBuilder buf = new StringBuilder();\r
500                 \r
501                 int colorType = pngHeader.getColorType();\r
502                 if ((colorType & 0x01) != 0) {\r
503                         buf.append("Indexed ");\r
504                 }\r
505                 if ((colorType & 0x02) != 0) {\r
506                         buf.append("Color ");\r
507 \r
508                 } else {\r
509                         buf.append("Greyscale ");\r
510                 }\r
511 \r
512                 if (colorType == 6 || pngHeader.hasTransparencyInformation()) {\r
513                         // 6:TrueColor または アルファ情報がある場合のみアルファ有りとする.\r
514                         buf.append("Alpha ");\r
515                 }\r
516 \r
517                 buf.append(pngHeader.getBitDepth() + "bit");\r
518                 \r
519                 return buf.toString().trim();\r
520         }\r
521 }\r
522 \r
523 /**\r
524  * ボタンレンダー.<br>\r
525  * @author seraphy\r
526  */\r
527 class ButtonCellRender extends DefaultTableCellRenderer {\r
528 \r
529         private static final long serialVersionUID = 1L;\r
530 \r
531         @Override\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
536         }\r
537 }\r
538 \r
539 /**\r
540  * ボタンエディタ.<br>\r
541  * @author seraphy\r
542  */\r
543 class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {\r
544 \r
545         private static final long serialVersionUID = 1L;\r
546 \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
556                                 }\r
557                         }\r
558                 });\r
559                 return btn;\r
560         }\r
561 \r
562         public Object getCellEditorValue() {\r
563                 return null;\r
564         }\r
565         \r
566 }\r
567 \r