-package charactermanaj.ui;\r
-\r
-import java.awt.BorderLayout;\r
-import java.awt.Color;\r
-import java.awt.Component;\r
-import java.awt.Container;\r
-import java.awt.GridBagConstraints;\r
-import java.awt.GridBagLayout;\r
-import java.awt.Insets;\r
-import java.awt.Toolkit;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.KeyEvent;\r
-import java.awt.event.WindowAdapter;\r
-import java.awt.event.WindowEvent;\r
-import java.net.URI;\r
-import java.sql.Timestamp;\r
-import java.util.Arrays;\r
-import java.util.Collections;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Map;\r
-import java.util.Properties;\r
-import java.util.concurrent.Semaphore;\r
-import java.util.logging.Level;\r
-import java.util.logging.Logger;\r
-\r
-import javax.swing.AbstractAction;\r
-import javax.swing.Action;\r
-import javax.swing.ActionMap;\r
-import javax.swing.BorderFactory;\r
-import javax.swing.Box;\r
-import javax.swing.InputMap;\r
-import javax.swing.JButton;\r
-import javax.swing.JComponent;\r
-import javax.swing.JDialog;\r
-import javax.swing.JFrame;\r
-import javax.swing.JLabel;\r
-import javax.swing.JOptionPane;\r
-import javax.swing.JPanel;\r
-import javax.swing.JPopupMenu;\r
-import javax.swing.JRootPane;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.JSeparator;\r
-import javax.swing.JTable;\r
-import javax.swing.JTextField;\r
-import javax.swing.KeyStroke;\r
-import javax.swing.UIManager;\r
-import javax.swing.event.DocumentEvent;\r
-import javax.swing.event.DocumentListener;\r
-import javax.swing.event.ListSelectionEvent;\r
-import javax.swing.event.ListSelectionListener;\r
-import javax.swing.event.TableModelEvent;\r
-import javax.swing.event.TableModelListener;\r
-import javax.swing.table.TableCellRenderer;\r
-import javax.swing.table.TableColumnModel;\r
-\r
-import charactermanaj.Main;\r
-import charactermanaj.model.AppConfig;\r
-import charactermanaj.model.CharacterData;\r
-import charactermanaj.model.PartsAuthorInfo;\r
-import charactermanaj.model.PartsCategory;\r
-import charactermanaj.model.PartsIdentifier;\r
-import charactermanaj.model.PartsManageData;\r
-import charactermanaj.model.PartsManageData.PartsKey;\r
-import charactermanaj.model.PartsManageData.PartsVersionInfo;\r
-import charactermanaj.model.PartsSpec;\r
-import charactermanaj.model.io.PartsInfoXMLReader;\r
-import charactermanaj.model.io.PartsInfoXMLWriter;\r
-import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;\r
-import charactermanaj.util.DesktopUtilities;\r
-import charactermanaj.util.ErrorMessageHelper;\r
-import charactermanaj.util.LocalizedResourcePropertyLoader;\r
-\r
-public class PartsManageDialog extends JDialog {\r
-\r
- private static final long serialVersionUID = 1L;\r
- \r
- protected static final String STRINGS_RESOURCE = "languages/partsmanagedialog";\r
- \r
- \r
- private static final Logger logger = Logger.getLogger(PartsManageDialog.class.getName());\r
-\r
- private CharacterData characterData;\r
- \r
- private PartsManageTableModel partsManageTableModel;\r
- \r
- private JTable partsManageTable;\r
- \r
- private JTextField txtHomepage;\r
- \r
- private JTextField txtAuthor;\r
- \r
- private boolean updated;\r
-\r
- \r
- public PartsManageDialog(JFrame parent, CharacterData characterData) {\r
- super(parent, true);\r
- \r
- if (characterData == null) {\r
- throw new IllegalArgumentException();\r
- }\r
- this.characterData = characterData;\r
- \r
- setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);\r
- addWindowListener(new WindowAdapter() {\r
- @Override\r
- public void windowClosing(WindowEvent e) {\r
- onClose();\r
- }\r
- });\r
-\r
- Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()\r
- .getLocalizedProperties(STRINGS_RESOURCE);\r
-\r
- setTitle(strings.getProperty("title"));\r
-\r
- Container contentPane = getContentPane();\r
- \r
- // パーツリストテーブル\r
- JPanel partsListPanel = new JPanel();\r
- partsListPanel.setBorder(BorderFactory.createCompoundBorder(\r
- BorderFactory.createEmptyBorder(5, 5, 5, 5), BorderFactory\r
- .createTitledBorder(strings.getProperty("partslist"))));\r
-\r
- GridBagLayout partsListPanelLayout = new GridBagLayout();\r
- partsListPanel.setLayout(partsListPanelLayout);\r
- \r
- partsManageTableModel = new PartsManageTableModel();\r
- partsManageTable = new JTable(partsManageTableModel) {\r
- private static final long serialVersionUID = 1L;\r
-\r
- @Override\r
- public Component prepareRenderer(TableCellRenderer renderer,\r
- int rowIdx, int columnIdx) {\r
- PartsManageTableModel.Columns column = PartsManageTableModel.Columns\r
- .values()[columnIdx];\r
- Component comp = super.prepareRenderer(renderer, rowIdx, columnIdx);\r
- PartsManageTableRow row = partsManageTableModel.getRow(rowIdx);\r
-\r
- Timestamp current = row.getTimestamp();\r
- Timestamp lastModified = row.getLastModified();\r
-\r
- boolean warnings = false;\r
-\r
- if (current != null && !current.equals(lastModified)) {\r
- // 現在のパーツの最終更新日と、パーツ管理情報の作成時のパーツの最終更新日が不一致の場合\r
- warnings = true;\r
- }\r
-\r
- // 背景色、警告行は赤色に\r
- if (warnings && column == PartsManageTableModel.Columns.LastModified) {\r
- AppConfig appConfig = AppConfig.getInstance();\r
- Color invalidBgColor = appConfig.getInvalidBgColor();\r
- comp.setBackground(invalidBgColor);\r
- } else {\r
- if (isCellSelected(rowIdx, columnIdx)) {\r
- comp.setBackground(getSelectionBackground());\r
- } else {\r
- comp.setBackground(getBackground());\r
- }\r
- }\r
-\r
- return comp;\r
- }\r
- };\r
- partsManageTable.setShowGrid(true);\r
- partsManageTable.setGridColor(AppConfig.getInstance().getGridColor());\r
- partsManageTableModel.adjustColumnModel(partsManageTable.getColumnModel());\r
- partsManageTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);\r
- partsManageTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);\r
-\r
- JScrollPane partsManageTableSP = new JScrollPane(partsManageTable);\r
- \r
- partsManageTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {\r
- public void valueChanged(ListSelectionEvent e) {\r
- if (!e.getValueIsAdjusting()) {\r
- onChangeSelection();\r
- }\r
- }\r
- });\r
- \r
- partsManageTableModel.addTableModelListener(new TableModelListener() {\r
- public void tableChanged(TableModelEvent e) {\r
- onTableDataChange(e.getFirstRow(), e.getLastRow());\r
- }\r
- });\r
- \r
- GridBagConstraints gbc = new GridBagConstraints();\r
- gbc.gridx = 0;\r
- gbc.gridy = 0;\r
- gbc.gridheight = 1;\r
- gbc.gridwidth = 4;\r
- gbc.anchor = GridBagConstraints.EAST;\r
- gbc.fill = GridBagConstraints.BOTH;\r
- gbc.insets = new Insets(3, 3, 3, 3);\r
- gbc.ipadx = 0;\r
- gbc.ipady = 0;\r
- gbc.weightx = 1.;\r
- gbc.weighty = 1.;\r
- partsListPanel.add(partsManageTableSP, gbc);\r
- \r
- Action actSortByName = new AbstractAction(strings.getProperty("sortByName")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onSortByName();\r
- }\r
- };\r
- Action actSortByAuthor = new AbstractAction(strings.getProperty("sortByAuthor")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onSortByAuthor();\r
- }\r
- };\r
- Action actSortByTimestamp = new AbstractAction(strings.getProperty("sortByTimestamp")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onSortByTimestamp();\r
- }\r
- };\r
- \r
- gbc.gridx = 0;\r
- gbc.gridy = 1;\r
- gbc.gridheight = 1;\r
- gbc.gridwidth = 1;\r
- gbc.weightx = 0.;\r
- gbc.weighty = 0.;\r
- partsListPanel.add(new JButton(actSortByName), gbc);\r
-\r
- gbc.gridx = 1;\r
- gbc.gridy = 1;\r
- gbc.weightx = 0.;\r
- gbc.weighty = 0.;\r
- partsListPanel.add(new JButton(actSortByAuthor), gbc);\r
-\r
- gbc.gridx = 2;\r
- gbc.gridy = 1;\r
- gbc.weightx = 0.;\r
- gbc.weighty = 0.;\r
- partsListPanel.add(new JButton(actSortByTimestamp), gbc);\r
-\r
- gbc.gridx = 3;\r
- gbc.gridy = 1;\r
- gbc.weightx = 1.;\r
- gbc.weighty = 0.;\r
- partsListPanel.add(Box.createHorizontalGlue(), gbc);\r
-\r
- contentPane.add(partsListPanel, BorderLayout.CENTER);\r
-\r
- // テーブルのコンテキストメニュー\r
- final JPopupMenu popupMenu = new JPopupMenu();\r
- Action actApplyAllLastModified = new AbstractAction(strings.getProperty("applyAllLastModified")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onApplyAllLastModified();\r
- }\r
- };\r
- Action actApplyAllDownloadURL = new AbstractAction(strings.getProperty("applyAllDownloadURL")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onApplyAllDownloadURL();\r
- }\r
- };\r
- Action actApplyAllVersion = new AbstractAction(strings.getProperty("applyAllVersion")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onApplyAllVersion();\r
- }\r
- };\r
- popupMenu.add(actApplyAllLastModified);\r
- popupMenu.add(new JSeparator());\r
- popupMenu.add(actApplyAllVersion);\r
- popupMenu.add(actApplyAllDownloadURL);\r
- \r
- partsManageTable.setComponentPopupMenu(popupMenu);\r
- \r
- // 作者情報パネル\r
- JPanel authorPanel = new JPanel();\r
- authorPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory\r
- .createEmptyBorder(5, 5, 5, 5), BorderFactory\r
- .createTitledBorder(strings.getProperty("author.info"))));\r
- GridBagLayout authorPanelLayout = new GridBagLayout();\r
- authorPanel.setLayout(authorPanelLayout);\r
- \r
- gbc.gridx = 0;\r
- gbc.gridy = 0;\r
- gbc.gridheight = 1;\r
- gbc.gridwidth = 1;\r
- gbc.anchor = GridBagConstraints.EAST;\r
- gbc.fill = GridBagConstraints.BOTH;\r
- gbc.insets = new Insets(3, 3, 3, 3);\r
- gbc.ipadx = 0;\r
- gbc.ipady = 0;\r
- gbc.weightx = 0.;\r
- gbc.weighty = 0.;\r
- authorPanel.add(new JLabel(strings.getProperty("author"), JLabel.RIGHT), gbc);\r
-\r
- gbc.gridx = 1;\r
- gbc.gridy = 0;\r
- gbc.gridwidth = 2;\r
- gbc.weightx = 1.;\r
- txtAuthor = new JTextField();\r
- authorPanel.add(txtAuthor, gbc);\r
-\r
- gbc.gridx = 0;\r
- gbc.gridy = 1;\r
- gbc.gridwidth = 1;\r
- gbc.weightx = 0.;\r
- authorPanel.add(new JLabel(strings.getProperty("homepage"), JLabel.RIGHT), gbc);\r
-\r
- gbc.gridx = 1;\r
- gbc.gridy = 1;\r
- gbc.gridwidth = 1;\r
- gbc.weightx = 1.;\r
- txtHomepage = new JTextField();\r
- authorPanel.add(txtHomepage, gbc);\r
-\r
- gbc.gridx = 2;\r
- gbc.gridy = 1;\r
- gbc.gridwidth = 1;\r
- gbc.weightx = 0.;\r
- Action actBrowseHomepage = new AbstractAction(strings.getProperty("open")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onBrosweHomepage();\r
- }\r
- };\r
- authorPanel.add(new JButton(actBrowseHomepage), gbc);\r
-\r
- if (!DesktopUtilities.isSupported()) {\r
- actBrowseHomepage.setEnabled(false);\r
- }\r
- \r
- txtAuthor.getDocument().addDocumentListener(new DocumentListener() {\r
- public void removeUpdate(DocumentEvent e) {\r
- onEditAuthor();\r
- }\r
- public void insertUpdate(DocumentEvent e) {\r
- onEditAuthor();\r
- }\r
- public void changedUpdate(DocumentEvent e) {\r
- onEditAuthor();\r
- }\r
- });\r
- txtHomepage.getDocument().addDocumentListener(new DocumentListener() {\r
- public void removeUpdate(DocumentEvent e) {\r
- onEditHomepage();\r
- }\r
- public void insertUpdate(DocumentEvent e) {\r
- onEditHomepage();\r
- }\r
- public void changedUpdate(DocumentEvent e) {\r
- onEditHomepage();\r
- }\r
- });\r
- \r
- \r
- // ボタンパネル\r
- JPanel btnPanel = new JPanel();\r
- btnPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 45));\r
- GridBagLayout btnPanelLayout = new GridBagLayout();\r
- btnPanel.setLayout(btnPanelLayout);\r
- \r
- Action actClose = new AbstractAction(strings.getProperty("cancel")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onClose();\r
- }\r
- };\r
- Action actOK = new AbstractAction(strings.getProperty("update")) {\r
- private static final long serialVersionUID = 1L;\r
- public void actionPerformed(ActionEvent e) {\r
- onOK();\r
- }\r
- };\r
- \r
- gbc.gridx = 0;\r
- gbc.gridy = 0;\r
- gbc.weightx = 1.;\r
- btnPanel.add(Box.createHorizontalGlue(), gbc);\r
- \r
- gbc.gridx = Main.isLinuxOrMacOSX() ? 2 : 1;\r
- gbc.gridy = 0;\r
- gbc.weightx = 0.;\r
- btnPanel.add(new JButton(actOK), gbc);\r
-\r
- gbc.gridx = Main.isLinuxOrMacOSX() ? 1 : 2;\r
- gbc.gridy = 0;\r
- gbc.weightx = 0.;\r
- btnPanel.add(new JButton(actClose), gbc);\r
- \r
- // ダイアログ下部\r
- JPanel southPanel = new JPanel(new BorderLayout());\r
- southPanel.add(authorPanel, BorderLayout.NORTH);\r
- southPanel.add(btnPanel, BorderLayout.SOUTH);\r
-\r
- contentPane.add(southPanel, BorderLayout.SOUTH);\r
- \r
- // キーボード\r
- \r
- Toolkit tk = Toolkit.getDefaultToolkit();\r
- JRootPane rootPane = getRootPane();\r
- InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);\r
- ActionMap am = rootPane.getActionMap();\r
- im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closePartsManageDialog");\r
- im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "closePartsManageDialog");\r
- am.put("closePartsManageDialog", actClose);\r
-\r
- // モデル構築\r
- partsManageTableModel.initModel(characterData);\r
- \r
- // ウィンドウ配置\r
- setSize(500, 400);\r
- setLocationRelativeTo(parent);\r
- }\r
-\r
- private Semaphore authorEditSemaphore = new Semaphore(1);\r
- \r
- protected void onChangeSelection() {\r
- try {\r
- authorEditSemaphore.acquire();\r
- try {\r
- int [] selRows = partsManageTable.getSelectedRows();\r
- HashSet<String> authors = new HashSet<String>();\r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- authors.add(row.getAuthor() == null ? "" : row.getAuthor());\r
- }\r
- if (authors.size() > 1) {\r
- AppConfig appConfig = AppConfig.getInstance();\r
- txtAuthor.setBackground(appConfig.getAuthorEditConflictBgColor());\r
- txtHomepage.setBackground(appConfig.getAuthorEditConflictBgColor());\r
- } else {\r
- Color bgColor = UIManager.getColor("TextField.background");\r
- if (bgColor == null) {\r
- bgColor = Color.white;\r
- }\r
- txtAuthor.setBackground(bgColor);\r
- txtHomepage.setBackground(bgColor);\r
- }\r
- if (authors.isEmpty()) {\r
- // 選択されているauthorがない場合は全部編集不可\r
- txtAuthor.setEditable(false);\r
- txtAuthor.setText("");\r
- txtHomepage.setEditable(false);\r
- txtHomepage.setText("");\r
- } else {\r
- // 選択されているAuthorが1つ以上あればAuthorは編集可\r
- txtAuthor.setEditable(true);\r
- txtHomepage.setEditable(true);\r
- if (authors.size() == 1) {\r
- // 選択されているAuthorが一個であれば、それを表示\r
- String author = authors.iterator().next();\r
- String homepage = partsManageTableModel.getHomepage(author);\r
- txtAuthor.setText(author);\r
- txtHomepage.setText(homepage);\r
- } else {\r
- // 選択されているAuthorが二個以上あれば編集可能だがテキストには表示しない.\r
- txtAuthor.setText("");\r
- txtHomepage.setText("");\r
- }\r
- }\r
- } finally {\r
- authorEditSemaphore.release();\r
- }\r
-\r
- } catch (InterruptedException ex) {\r
- ErrorMessageHelper.showErrorDialog(this, ex);\r
-\r
- } catch (RuntimeException ex) {\r
- ErrorMessageHelper.showErrorDialog(this, ex);\r
- }\r
- }\r
- \r
- protected void onTableDataChange(int firstRow, int lastRow) {\r
- onChangeSelection();\r
- }\r
- \r
- protected void onApplyAllLastModified() {\r
- int[] selRows = partsManageTable.getSelectedRows();\r
- if (selRows.length == 0) {\r
- Toolkit tk = Toolkit.getDefaultToolkit();\r
- tk.beep();\r
- return;\r
- }\r
- Arrays.sort(selRows);\r
-\r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- Timestamp dt = row.getTimestamp();\r
- row.setLastModified(dt);\r
- }\r
- partsManageTableModel.fireTableRowsUpdated(selRows[0],\r
- selRows[selRows.length - 1]);\r
- }\r
-\r
- protected void onApplyAllDownloadURL() {\r
- int[] selRows = partsManageTable.getSelectedRows();\r
- if (selRows.length == 0) {\r
- Toolkit tk = Toolkit.getDefaultToolkit();\r
- tk.beep();\r
- return;\r
- }\r
- Arrays.sort(selRows);\r
-\r
- HashSet<String> authors = new HashSet<String>();\r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- authors.add(row.getAuthor() == null ? "" : row.getAuthor());\r
- }\r
-\r
- Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()\r
- .getLocalizedProperties(STRINGS_RESOURCE);\r
-\r
- if (authors.size() > 1) {\r
- if (JOptionPane.showConfirmDialog(this,\r
- strings.getProperty("confirm.authorConflict"),\r
- strings.getProperty("confirm"),\r
- JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {\r
- return;\r
- }\r
- }\r
- \r
- PartsManageTableRow firstRow = partsManageTableModel.getRow(selRows[0]);\r
- String downloadURL = firstRow.getDownloadURL();\r
- if (downloadURL == null) {\r
- downloadURL = "";\r
- }\r
- String downloadURL_new = JOptionPane.showInputDialog(this, strings.getProperty("input.downloadURL"), downloadURL);\r
- if (downloadURL_new == null || downloadURL.equals(downloadURL_new)) {\r
- // キャンセルされたか、内容に変化ない場合は何もしない\r
- return;\r
- }\r
- \r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- row.setDownloadURL(downloadURL_new);\r
-\r
- Timestamp dt = row.getTimestamp();\r
- row.setLastModified(dt);\r
- }\r
- partsManageTableModel.fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);\r
- }\r
- \r
- protected void onApplyAllVersion() {\r
- Toolkit tk = Toolkit.getDefaultToolkit();\r
- int[] selRows = partsManageTable.getSelectedRows();\r
- if (selRows.length == 0) {\r
- tk.beep();\r
- return;\r
- }\r
- Arrays.sort(selRows);\r
-\r
- HashSet<String> authors = new HashSet<String>();\r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- authors.add(row.getAuthor() == null ? "" : row.getAuthor());\r
- }\r
-\r
- Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()\r
- .getLocalizedProperties(STRINGS_RESOURCE);\r
-\r
- if (authors.size() > 1) {\r
- if (JOptionPane.showConfirmDialog(this,\r
- strings.getProperty("confirm.authorConflict"),\r
- strings.getProperty("confirm"),\r
- JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {\r
- return;\r
- }\r
- }\r
-\r
- PartsManageTableRow firstRow = partsManageTableModel.getRow(selRows[0]);\r
- double version = firstRow.getVersion();\r
- String strVersion = (version < 0) ? "" : Double.toString(version);\r
- String strVersion_new = JOptionPane.showInputDialog(this,\r
- strings.getProperty("input.version"), strVersion);\r
- if (strVersion_new == null || strVersion.equals(strVersion_new)) {\r
- // キャンセルされたか、内容に変化ない場合は何もしない\r
- return;\r
- }\r
- double version_new;\r
- try {\r
- version_new = Double.parseDouble(strVersion_new);\r
- } catch (Exception ex) {\r
- // 数値として不正であれば何もしない.\r
- tk.beep();\r
- return;\r
- }\r
- \r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- row.setVersion(version_new);\r
-\r
- Timestamp dt = row.getTimestamp();\r
- row.setLastModified(dt);\r
- }\r
- partsManageTableModel.fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);\r
- }\r
- \r
- protected void onEditHomepage() {\r
- try {\r
- if (!authorEditSemaphore.tryAcquire()) {\r
- return;\r
- }\r
- try {\r
- String author = txtAuthor.getText();\r
- String homepage = txtHomepage.getText();\r
- partsManageTableModel.setHomepage(author, homepage);\r
- } finally {\r
- authorEditSemaphore.release();\r
- }\r
- } catch (Exception ex) {\r
- ErrorMessageHelper.showErrorDialog(this, ex);\r
- }\r
- }\r
-\r
- protected void onEditAuthor() {\r
- try {\r
- if (!authorEditSemaphore.tryAcquire()) {\r
- return;\r
- }\r
- try {\r
- String author = txtAuthor.getText();\r
- int[] selRows = partsManageTable.getSelectedRows();\r
- int firstRow = -1;\r
- int lastRow = Integer.MAX_VALUE;\r
- for (int selRow : selRows) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(selRow);\r
- String oldValue = row.getAuthor();\r
- if (oldValue == null || !oldValue.equals(author)) {\r
- row.setAuthor(author);\r
-\r
- Timestamp dt = row.getTimestamp();\r
- row.setLastModified(dt);\r
-\r
- firstRow = Math.max(firstRow, selRow);\r
- lastRow = Math.min(lastRow, selRow);\r
- }\r
- }\r
- \r
- String homepage = partsManageTableModel.getHomepage(author);\r
- if (homepage == null) {\r
- homepage = "";\r
- }\r
- txtHomepage.setText(homepage);\r
- \r
- if (firstRow >= 0) {\r
- partsManageTable.repaint();\r
- }\r
- } finally {\r
- authorEditSemaphore.release(); \r
- }\r
- } catch (Exception ex) {\r
- ErrorMessageHelper.showErrorDialog(this, ex);\r
- }\r
- }\r
- \r
- protected void onClose() {\r
- Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()\r
- .getLocalizedProperties(STRINGS_RESOURCE);\r
- if (JOptionPane.showConfirmDialog(this,\r
- strings.getProperty("confirm.cancel"),\r
- strings.getProperty("confirm"),\r
- JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {\r
- return;\r
- }\r
- updated = false;\r
- dispose();\r
- }\r
- \r
- protected void onBrosweHomepage() {\r
- Toolkit tk = Toolkit.getDefaultToolkit();\r
- String homepage = txtHomepage.getText();\r
- if (homepage == null || homepage.trim().length() == 0) {\r
- tk.beep();\r
- return;\r
- }\r
- try {\r
- URI uri = new URI(homepage);\r
- DesktopUtilities.browse(uri);\r
-\r
- } catch (Exception ex) {\r
- tk.beep();\r
- logger.log(Level.INFO, "browse failed. : " + homepage, ex);\r
- }\r
- }\r
- \r
- protected void onSortByAuthor() {\r
- partsManageTableModel.sortByAuthor();\r
- }\r
- \r
- protected void onSortByName() {\r
- partsManageTableModel.sortByName();\r
- }\r
- \r
- protected void onSortByTimestamp() {\r
- partsManageTableModel.sortByTimestamp();\r
- }\r
- \r
- protected void onOK() {\r
- if (partsManageTable.isEditing()) {\r
- Toolkit tk = Toolkit.getDefaultToolkit();\r
- tk.beep();\r
- return;\r
- }\r
- \r
- int mx = partsManageTableModel.getRowCount();\r
-\r
- // 作者ごとのホームページ情報の取得\r
- // (同一作者につきホームページは一つ)\r
- HashMap<String, PartsAuthorInfo> authorInfoMap = new HashMap<String, PartsAuthorInfo>();\r
- for (int idx = 0; idx < mx; idx++) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(idx);\r
- String author = row.getAuthor();\r
- String homepage = row.getHomepage();\r
- if (author != null && author.trim().length() > 0) {\r
- PartsAuthorInfo authorInfo = authorInfoMap.get(author.trim());\r
- if (authorInfo == null) {\r
- authorInfo = new PartsAuthorInfo();\r
- authorInfo.setAuthor(author.trim());\r
- authorInfoMap.put(authorInfo.getAuthor(), authorInfo);\r
- }\r
- authorInfo.setHomePage(homepage);\r
- }\r
- }\r
-\r
- PartsManageData partsManageData = new PartsManageData();\r
- \r
- // パーツごとの作者とバージョン、ダウンロード先の取得\r
- for (int idx = 0; idx < mx; idx++) {\r
- PartsManageTableRow row = partsManageTableModel.getRow(idx);\r
- \r
- String author = row.getAuthor();\r
- PartsAuthorInfo partsAuthorInfo = null;\r
- if (author != null && author.trim().length() > 0) {\r
- partsAuthorInfo = authorInfoMap.get(author.trim());\r
- }\r
- \r
- double version = row.getVersion();\r
- String downloadURL = row.getDownloadURL();\r
- String localizedName = row.getLocalizedName();\r
- Timestamp lastModified = row.getLastModified();\r
- \r
- PartsManageData.PartsVersionInfo versionInfo = new PartsManageData.PartsVersionInfo();\r
- versionInfo.setVersion(version);\r
- versionInfo.setDownloadURL(downloadURL);\r
- versionInfo.setLastModified(lastModified);\r
-\r
- PartsIdentifier partsIdentifier = row.getPartsIdentifier();\r
- \r
- PartsManageData.PartsKey partsKey = new PartsManageData.PartsKey(partsIdentifier);\r
- partsManageData.putPartsInfo(partsKey, localizedName,\r
- partsAuthorInfo, versionInfo);\r
- }\r
- \r
- // パーツ管理情報を書き込む.\r
- PartsInfoXMLWriter xmlWriter = new PartsInfoXMLWriter();\r
- try {\r
- URI docBase = characterData.getDocBase();\r
- xmlWriter.savePartsManageData(docBase, partsManageData);\r
-\r
- } catch (Exception ex) {\r
- ErrorMessageHelper.showErrorDialog(this, ex);\r
- return;\r
- }\r
- \r
- updated = true;\r
- dispose();\r
- }\r
-\r
- /**\r
- * パーツ管理情報が更新されたか?\r
- * \r
- * @return 更新された場合はtrue、そうでなければfalse\r
- */\r
- public boolean isUpdated() {\r
- return updated;\r
- }\r
-}\r
-\r
-class PartsManageTableRow {\r
- \r
- private PartsIdentifier partsIdentifier;\r
- \r
- private Timestamp timestamp;\r
- \r
- private String localizedName;\r
- \r
- private String author;\r
- \r
- private String homepage;\r
- \r
- private String downloadURL;\r
- \r
- private double version;\r
- \r
- private Timestamp lastModified;\r
-\r
- public PartsManageTableRow(PartsIdentifier partsIdentifier,\r
- PartsSpec partsSpec, Timestamp lastModified) {\r
- if (partsIdentifier == null || partsSpec == null) {\r
- throw new IllegalArgumentException();\r
- }\r
- this.partsIdentifier = partsIdentifier;\r
- this.localizedName = partsIdentifier.getLocalizedPartsName();\r
-\r
- this.timestamp = new Timestamp(partsSpec.getPartsFiles().lastModified());\r
- \r
- this.lastModified = lastModified;\r
- \r
- PartsAuthorInfo autherInfo = partsSpec.getAuthorInfo();\r
- if (autherInfo != null) {\r
- author = autherInfo.getAuthor();\r
- homepage = autherInfo.getHomePage();\r
- }\r
- if (author == null) {\r
- author = "";\r
- }\r
- if (homepage == null) {\r
- homepage = "";\r
- }\r
- downloadURL = partsSpec.getDownloadURL();\r
- version = partsSpec.getVersion();\r
- }\r
- \r
- public PartsIdentifier getPartsIdentifier() {\r
- return partsIdentifier;\r
- }\r
- \r
- public Timestamp getTimestamp() {\r
- return timestamp;\r
- }\r
-\r
- public String getLocalizedName() {\r
- return localizedName;\r
- }\r
- \r
- public void setLocalizedName(String localizedName) {\r
- if (localizedName == null || localizedName.trim().length() == 0) {\r
- throw new IllegalArgumentException();\r
- }\r
- this.localizedName = localizedName;\r
- }\r
- \r
- public String getAuthor() {\r
- return author;\r
- }\r
- \r
- public String getDownloadURL() {\r
- return downloadURL;\r
- }\r
- \r
- public double getVersion() {\r
- return version;\r
- }\r
- \r
- public void setAuthor(String author) {\r
- this.author = author;\r
- }\r
- \r
- public void setDownloadURL(String downloadURL) {\r
- this.downloadURL = downloadURL;\r
- }\r
- \r
- public void setVersion(double version) {\r
- this.version = version;\r
- }\r
- \r
- public String getHomepage() {\r
- return homepage;\r
- }\r
- \r
- public void setHomepage(String homepage) {\r
- this.homepage = homepage;\r
- }\r
- \r
- public Timestamp getLastModified() {\r
- return lastModified;\r
- }\r
-\r
- public void setLastModified(Timestamp lastModified) {\r
- this.lastModified = lastModified;\r
- }\r
-}\r
-\r
-class PartsManageTableModel extends AbstractTableModelWithComboBoxModel<PartsManageTableRow> {\r
-\r
- private static final long serialVersionUID = 1L;\r
-\r
- private static final Logger logger = Logger\r
- .getLogger(PartsManageTableModel.class.getName());\r
-\r
- private static Properties strings = LocalizedResourcePropertyLoader\r
- .getCachedInstance().getLocalizedProperties(\r
- PartsManageDialog.STRINGS_RESOURCE);\r
-\r
- /**\r
- * カラムの定義\r
- */\r
- public enum Columns {\r
- PartsID("column.partsid", false, String.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getPartsIdentifier().getPartsName();\r
- }\r
- },\r
- LastModified("column.lastmodified", false, String.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getTimestamp().toString();\r
- }\r
- },\r
- Category("column.category", false, String.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getPartsIdentifier().getPartsCategory()\r
- .getLocalizedCategoryName();\r
- }\r
- },\r
- PartsName("column.partsname", true, String.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getLocalizedName();\r
- }\r
- @Override\r
- public void setValue(PartsManageTableRow row, Object value) {\r
- String localizedName = (String) value;\r
- if (localizedName != null && localizedName.trim().length() > 0) {\r
- String oldValue = row.getLocalizedName();\r
- if (oldValue != null && oldValue.equals(localizedName)) {\r
- return; // 変化なし\r
- }\r
- row.setLocalizedName(localizedName);\r
- }\r
- }\r
- },\r
- Author("column.author", true, String.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getAuthor();\r
- }\r
- @Override\r
- public void setValue(PartsManageTableRow row, Object value) {\r
- String author = (String) value;\r
- if (author == null) {\r
- author = "";\r
- }\r
- String oldValue = row.getAuthor();\r
- if (oldValue != null && oldValue.equals(author)) {\r
- return; // 変化なし\r
- }\r
- row.setAuthor(author);\r
- }\r
- },\r
- Version("column.version", true, Double.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getVersion() > 0 ? row.getVersion() : null;\r
- }\r
- @Override\r
- public void setValue(PartsManageTableRow row, Object value) {\r
- Double version = (Double) value;\r
- if (version == null || version.doubleValue() <= 0) {\r
- version = Double.valueOf(0.);\r
- }\r
- Double oldValue = row.getVersion();\r
- if (oldValue != null && oldValue.equals(version)) {\r
- return; // 変化なし\r
- }\r
- row.setVersion(version);\r
- }\r
- },\r
- DownloadURL("column.downloadURL", true, String.class) {\r
- @Override\r
- public Object getValue(PartsManageTableRow row) {\r
- return row.getDownloadURL();\r
- }\r
- @Override\r
- public void setValue(PartsManageTableRow row, Object value) {\r
- String downloadURL = (String) value;\r
- if (downloadURL == null) {\r
- downloadURL = "";\r
- }\r
- String oldValue = row.getDownloadURL();\r
- if (oldValue != null && oldValue.equals(downloadURL)) {\r
- return; // 変化なし\r
- }\r
- row.setDownloadURL(downloadURL);\r
- }\r
- };\r
-\r
- private final Class<?> columnClass;\r
-\r
- private final boolean editable;\r
-\r
- private final String columnName;\r
-\r
- private String displayName;\r
-\r
- private int width;\r
-\r
- private Columns(String columnName, boolean editable,\r
- Class<?> columnClass) {\r
- this.columnName = columnName;\r
- this.editable = editable;\r
- this.columnClass = columnClass;\r
- }\r
-\r
- public abstract Object getValue(PartsManageTableRow row);\r
-\r
- public boolean isEditable() {\r
- return editable;\r
- }\r
-\r
- public Class<?> getColumnClass() {\r
- return columnClass;\r
- }\r
-\r
- public String getDisplayName() {\r
- init();\r
- return displayName;\r
- }\r
-\r
- public int getWidth() {\r
- init();\r
- return width;\r
- }\r
-\r
- public void setValue(PartsManageTableRow row, Object value) {\r
- // 何もしない.\r
- }\r
-\r
- private void init() {\r
- if (displayName != null) {\r
- return;\r
- }\r
- displayName = strings.getProperty(columnName);\r
- width = Integer\r
- .parseInt(strings.getProperty(columnName + ".width"));\r
- }\r
- }\r
-\r
- \r
- public int getColumnCount() {\r
- return Columns.values().length;\r
- }\r
- \r
- @Override\r
- public String getColumnName(int column) {\r
- return Columns.values()[column].getDisplayName();\r
- }\r
- \r
- public void adjustColumnModel(TableColumnModel columnModel) {\r
- Columns[] columns = Columns.values();\r
- for (int idx = 0; idx < columns.length; idx++) {\r
- columnModel.getColumn(idx).setPreferredWidth(\r
- columns[idx].getWidth());\r
- }\r
- }\r
-\r
- public Object getValueAt(int rowIndex, int columnIndex) {\r
- PartsManageTableRow row = getRow(rowIndex);\r
- Columns column = Columns.values()[columnIndex];\r
- return column.getValue(row);\r
- }\r
- \r
- @Override\r
- public void setValueAt(Object aValue, int rowIndex, int columnIndex) {\r
- PartsManageTableRow row = getRow(rowIndex);\r
- Columns column = Columns.values()[columnIndex];\r
- if (!column.isEditable()) {\r
- return;\r
- }\r
- column.setValue(row, aValue);\r
-\r
- // 更新日を最新にする\r
- Timestamp dt = row.getTimestamp();\r
- row.setLastModified(dt);\r
-\r
- // 変更通知\r
- fireTableRowsUpdated(rowIndex, columnIndex);\r
- }\r
- \r
- @Override\r
- public Class<?> getColumnClass(int columnIndex) {\r
- Columns column = Columns.values()[columnIndex];\r
- return column.getColumnClass();\r
- }\r
- \r
- @Override\r
- public boolean isCellEditable(int rowIndex, int columnIndex) {\r
- Columns column = Columns.values()[columnIndex];\r
- return column.isEditable();\r
- }\r
- \r
- public void initModel(CharacterData characterData) {\r
- if (characterData == null) {\r
- throw new IllegalArgumentException();\r
- }\r
- clear();\r
-\r
- // 既存のパーツ管理情報ファイルがあれば読み込む\r
- URI docBase = characterData.getDocBase();\r
- PartsManageData partsManageData = null;\r
- if (docBase != null) {\r
- try {\r
- PartsInfoXMLReader reader = new PartsInfoXMLReader();\r
- partsManageData = reader.loadPartsManageData(docBase);\r
-\r
- } catch (Exception ex) {\r
- logger.log(Level.WARNING, ex.toString(), ex);\r
- }\r
- }\r
- if (partsManageData == null) {\r
- partsManageData = new PartsManageData();\r
- }\r
-\r
- for (PartsCategory partsCategory : characterData.getPartsCategories()) {\r
- for (Map.Entry<PartsIdentifier, PartsSpec> entry : characterData\r
- .getPartsSpecMap(partsCategory).entrySet()) {\r
- PartsIdentifier partsIdentifier = entry.getKey();\r
- PartsSpec partsSpec = entry.getValue();\r
- \r
- // パーツ管理情報ファイルから、パーツ管理情報を設定した時点の\r
- // ファイルサイズや更新日時などを読み取る.\r
- PartsKey partsKey = new PartsKey(partsIdentifier);\r
- PartsVersionInfo versionInfo = partsManageData\r
- .getVersion(partsKey);\r
-\r
- Timestamp lastModified = null;\r
-\r
- if (versionInfo != null) {\r
- lastModified = versionInfo.getLastModified();\r
- }\r
-\r
- PartsManageTableRow row = new PartsManageTableRow(\r
- partsIdentifier, partsSpec, lastModified);\r
- addRow(row);\r
- }\r
- }\r
-\r
- sortByAuthor();\r
- }\r
-\r
- /**\r
- * ホームページを設定する.<br>\r
- * ホームページはAuthorに対して1つであるが、Authorが自由編集可能であるため便宜的にRowに持たせている.<br>\r
- * 結果として同じAuthorに対して同じ値を設定する必要がある.<br>\r
- * ホームページはテーブルに表示されないのでリスナーへの通知は行わない.<br>\r
- * \r
- * @param author\r
- * 作者、空またはnullは何もしない.\r
- * @param homepage\r
- * ホームページ\r
- */\r
- public void setHomepage(String author, String homepage) {\r
- if (author == null || author.length() == 0) {\r
- return;\r
- }\r
- for (PartsManageTableRow row : elements) {\r
- String targetAuthor = row.getAuthor();\r
- if (targetAuthor == null) {\r
- targetAuthor = "";\r
- }\r
- if (targetAuthor.equals(author)) {\r
- row.setHomepage(homepage);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * ホームページを取得する.<br>\r
- * 該当する作者がないか、作者がnullまたは空の場合は常にnullを返す.<br>\r
- * \r
- * @param author\r
- * 作者\r
- * @return ホームページ、またはnull\r
- */\r
- public String getHomepage(String author) {\r
- if (author == null || author.length() == 0) {\r
- return null;\r
- }\r
- for (PartsManageTableRow row : elements) {\r
- String targetAuthor = row.getAuthor();\r
- if (targetAuthor == null) {\r
- targetAuthor = "";\r
- }\r
- if (targetAuthor.equals(author)) {\r
- return row.getHomepage();\r
- }\r
- }\r
- return null;\r
- }\r
- \r
- protected static final Comparator<PartsManageTableRow> NAMED_SORTER\r
- = new Comparator<PartsManageTableRow>() {\r
- public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {\r
- // カテゴリで順序づけ\r
- int ret = o1.getPartsIdentifier().getPartsCategory().compareTo(\r
- o2.getPartsIdentifier().getPartsCategory());\r
- if (ret == 0) {\r
- // 表示名で順序づけ\r
- String lnm1 = o1.getLocalizedName();\r
- String lnm2 = o2.getLocalizedName();\r
- if (lnm1 == null) {\r
- lnm1 = "";\r
- }\r
- if (lnm2 == null) {\r
- lnm2 = "";\r
- }\r
- ret = lnm1.compareTo(lnm2);\r
- }\r
- if (ret == 0) {\r
- // それでも判定できなければ元の識別子で判定する.\r
- ret = o1.getPartsIdentifier().compareTo(o2.getPartsIdentifier());\r
- }\r
- return ret;\r
- }\r
- };\r
- \r
- public void sortByName() {\r
- Collections.sort(elements, NAMED_SORTER);\r
- fireTableDataChanged();\r
- }\r
- \r
- public void sortByTimestamp() {\r
- Collections.sort(elements, new Comparator<PartsManageTableRow>() {\r
- public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {\r
- // 更新日で順序づけ (新しいもの順)\r
- int ret = o1.getTimestamp().compareTo(o2.getTimestamp()) * -1;\r
- if (ret == 0) {\r
- // それでも判定できなければ名前順と同じ\r
- ret = NAMED_SORTER.compare(o1, o2);\r
- }\r
- return ret;\r
- }\r
- });\r
- fireTableDataChanged();\r
- }\r
-\r
- public void sortByAuthor() {\r
- Collections.sort(elements, new Comparator<PartsManageTableRow>() {\r
- public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {\r
- // 作者で順序づけ\r
- String author1 = o1.getAuthor();\r
- String author2 = o2.getAuthor();\r
- if (author1 == null) {\r
- author1 = "";\r
- }\r
- if (author2 == null) {\r
- author2 = "";\r
- }\r
- int ret = author1.compareTo(author2);\r
- if (ret == 0) {\r
- // それでも判定できなければ名前順と同じ\r
- ret = NAMED_SORTER.compare(o1, o2);\r
- }\r
- return ret;\r
- }\r
- });\r
- fireTableDataChanged();\r
- }\r
-}\r
+package charactermanaj.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.URI;
+import java.sql.Timestamp;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Semaphore;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JRootPane;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.UIManager;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumnModel;
+
+import charactermanaj.Main;
+import charactermanaj.model.AppConfig;
+import charactermanaj.model.CharacterData;
+import charactermanaj.model.PartsAuthorInfo;
+import charactermanaj.model.PartsCategory;
+import charactermanaj.model.PartsIdentifier;
+import charactermanaj.model.PartsManageData;
+import charactermanaj.model.PartsManageData.PartsKey;
+import charactermanaj.model.PartsManageData.PartsVersionInfo;
+import charactermanaj.model.PartsSpec;
+import charactermanaj.model.io.PartsInfoXMLReader;
+import charactermanaj.model.io.PartsInfoXMLWriter;
+import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;
+import charactermanaj.util.DesktopUtilities;
+import charactermanaj.util.ErrorMessageHelper;
+import charactermanaj.util.LocalizedResourcePropertyLoader;
+
+public class PartsManageDialog extends JDialog {
+
+ private static final long serialVersionUID = 1L;
+
+ protected static final String STRINGS_RESOURCE = "languages/partsmanagedialog";
+
+
+ private static final Logger logger = Logger.getLogger(PartsManageDialog.class.getName());
+
+ private CharacterData characterData;
+
+ private PartsManageTableModel partsManageTableModel;
+
+ private JTable partsManageTable;
+
+ private JTextField txtHomepage;
+
+ private JTextField txtAuthor;
+
+ private boolean updated;
+
+
+ public PartsManageDialog(JFrame parent, CharacterData characterData) {
+ super(parent, true);
+
+ if (characterData == null) {
+ throw new IllegalArgumentException();
+ }
+ this.characterData = characterData;
+
+ setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ onClose();
+ }
+ });
+
+ Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
+ .getLocalizedProperties(STRINGS_RESOURCE);
+
+ setTitle(strings.getProperty("title"));
+
+ Container contentPane = getContentPane();
+
+ // パーツリストテーブル
+ JPanel partsListPanel = new JPanel();
+ partsListPanel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createEmptyBorder(5, 5, 5, 5), BorderFactory
+ .createTitledBorder(strings.getProperty("partslist"))));
+
+ GridBagLayout partsListPanelLayout = new GridBagLayout();
+ partsListPanel.setLayout(partsListPanelLayout);
+
+ partsManageTableModel = new PartsManageTableModel();
+ partsManageTable = new JTable(partsManageTableModel) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Component prepareRenderer(TableCellRenderer renderer,
+ int rowIdx, int columnIdx) {
+ PartsManageTableModel.Columns column = PartsManageTableModel.Columns
+ .values()[columnIdx];
+ Component comp = super.prepareRenderer(renderer, rowIdx, columnIdx);
+ PartsManageTableRow row = partsManageTableModel.getRow(rowIdx);
+
+ Timestamp current = row.getTimestamp();
+ Timestamp lastModified = row.getLastModified();
+
+ boolean warnings = false;
+
+ if (current != null && !current.equals(lastModified)) {
+ // 現在のパーツの最終更新日と、パーツ管理情報の作成時のパーツの最終更新日が不一致の場合
+ warnings = true;
+ }
+
+ // 背景色、警告行は赤色に
+ if (warnings && column == PartsManageTableModel.Columns.LastModified) {
+ AppConfig appConfig = AppConfig.getInstance();
+ Color invalidBgColor = appConfig.getInvalidBgColor();
+ comp.setBackground(invalidBgColor);
+ } else {
+ if (isCellSelected(rowIdx, columnIdx)) {
+ comp.setBackground(getSelectionBackground());
+ } else {
+ comp.setBackground(getBackground());
+ }
+ }
+
+ return comp;
+ }
+ };
+ partsManageTable.setShowGrid(true);
+ partsManageTable.setGridColor(AppConfig.getInstance().getGridColor());
+ partsManageTableModel.adjustColumnModel(partsManageTable.getColumnModel());
+ partsManageTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+ partsManageTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
+
+ JScrollPane partsManageTableSP = new JScrollPane(partsManageTable);
+
+ partsManageTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ if (!e.getValueIsAdjusting()) {
+ onChangeSelection();
+ }
+ }
+ });
+
+ partsManageTableModel.addTableModelListener(new TableModelListener() {
+ public void tableChanged(TableModelEvent e) {
+ onTableDataChange(e.getFirstRow(), e.getLastRow());
+ }
+ });
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.gridheight = 1;
+ gbc.gridwidth = 4;
+ gbc.anchor = GridBagConstraints.EAST;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.insets = new Insets(3, 3, 3, 3);
+ gbc.ipadx = 0;
+ gbc.ipady = 0;
+ gbc.weightx = 1.;
+ gbc.weighty = 1.;
+ partsListPanel.add(partsManageTableSP, gbc);
+
+ Action actSortByName = new AbstractAction(strings.getProperty("sortByName")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onSortByName();
+ }
+ };
+ Action actSortByAuthor = new AbstractAction(strings.getProperty("sortByAuthor")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onSortByAuthor();
+ }
+ };
+ Action actSortByTimestamp = new AbstractAction(strings.getProperty("sortByTimestamp")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onSortByTimestamp();
+ }
+ };
+
+ gbc.gridx = 0;
+ gbc.gridy = 1;
+ gbc.gridheight = 1;
+ gbc.gridwidth = 1;
+ gbc.weightx = 0.;
+ gbc.weighty = 0.;
+ partsListPanel.add(new JButton(actSortByName), gbc);
+
+ gbc.gridx = 1;
+ gbc.gridy = 1;
+ gbc.weightx = 0.;
+ gbc.weighty = 0.;
+ partsListPanel.add(new JButton(actSortByAuthor), gbc);
+
+ gbc.gridx = 2;
+ gbc.gridy = 1;
+ gbc.weightx = 0.;
+ gbc.weighty = 0.;
+ partsListPanel.add(new JButton(actSortByTimestamp), gbc);
+
+ gbc.gridx = 3;
+ gbc.gridy = 1;
+ gbc.weightx = 1.;
+ gbc.weighty = 0.;
+ partsListPanel.add(Box.createHorizontalGlue(), gbc);
+
+ contentPane.add(partsListPanel, BorderLayout.CENTER);
+
+ // テーブルのコンテキストメニュー
+ final JPopupMenu popupMenu = new JPopupMenu();
+ Action actApplyAllLastModified = new AbstractAction(strings.getProperty("applyAllLastModified")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onApplyAllLastModified();
+ }
+ };
+ Action actApplyAllDownloadURL = new AbstractAction(strings.getProperty("applyAllDownloadURL")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onApplyAllDownloadURL();
+ }
+ };
+ Action actApplyAllVersion = new AbstractAction(strings.getProperty("applyAllVersion")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onApplyAllVersion();
+ }
+ };
+ popupMenu.add(actApplyAllLastModified);
+ popupMenu.add(new JSeparator());
+ popupMenu.add(actApplyAllVersion);
+ popupMenu.add(actApplyAllDownloadURL);
+
+ partsManageTable.setComponentPopupMenu(popupMenu);
+
+ // 作者情報パネル
+ JPanel authorPanel = new JPanel();
+ authorPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory
+ .createEmptyBorder(5, 5, 5, 5), BorderFactory
+ .createTitledBorder(strings.getProperty("author.info"))));
+ GridBagLayout authorPanelLayout = new GridBagLayout();
+ authorPanel.setLayout(authorPanelLayout);
+
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.gridheight = 1;
+ gbc.gridwidth = 1;
+ gbc.anchor = GridBagConstraints.EAST;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.insets = new Insets(3, 3, 3, 3);
+ gbc.ipadx = 0;
+ gbc.ipady = 0;
+ gbc.weightx = 0.;
+ gbc.weighty = 0.;
+ authorPanel.add(new JLabel(strings.getProperty("author"), JLabel.RIGHT), gbc);
+
+ gbc.gridx = 1;
+ gbc.gridy = 0;
+ gbc.gridwidth = 2;
+ gbc.weightx = 1.;
+ txtAuthor = new JTextField();
+ authorPanel.add(txtAuthor, gbc);
+
+ gbc.gridx = 0;
+ gbc.gridy = 1;
+ gbc.gridwidth = 1;
+ gbc.weightx = 0.;
+ authorPanel.add(new JLabel(strings.getProperty("homepage"), JLabel.RIGHT), gbc);
+
+ gbc.gridx = 1;
+ gbc.gridy = 1;
+ gbc.gridwidth = 1;
+ gbc.weightx = 1.;
+ txtHomepage = new JTextField();
+ authorPanel.add(txtHomepage, gbc);
+
+ gbc.gridx = 2;
+ gbc.gridy = 1;
+ gbc.gridwidth = 1;
+ gbc.weightx = 0.;
+ Action actBrowseHomepage = new AbstractAction(strings.getProperty("open")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onBrosweHomepage();
+ }
+ };
+ authorPanel.add(new JButton(actBrowseHomepage), gbc);
+
+ if (!DesktopUtilities.isSupported()) {
+ actBrowseHomepage.setEnabled(false);
+ }
+
+ txtAuthor.getDocument().addDocumentListener(new DocumentListener() {
+ public void removeUpdate(DocumentEvent e) {
+ onEditAuthor();
+ }
+ public void insertUpdate(DocumentEvent e) {
+ onEditAuthor();
+ }
+ public void changedUpdate(DocumentEvent e) {
+ onEditAuthor();
+ }
+ });
+ txtHomepage.getDocument().addDocumentListener(new DocumentListener() {
+ public void removeUpdate(DocumentEvent e) {
+ onEditHomepage();
+ }
+ public void insertUpdate(DocumentEvent e) {
+ onEditHomepage();
+ }
+ public void changedUpdate(DocumentEvent e) {
+ onEditHomepage();
+ }
+ });
+
+
+ // ボタンパネル
+ JPanel btnPanel = new JPanel();
+ btnPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 45));
+ GridBagLayout btnPanelLayout = new GridBagLayout();
+ btnPanel.setLayout(btnPanelLayout);
+
+ Action actClose = new AbstractAction(strings.getProperty("cancel")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onClose();
+ }
+ };
+ Action actOK = new AbstractAction(strings.getProperty("update")) {
+ private static final long serialVersionUID = 1L;
+ public void actionPerformed(ActionEvent e) {
+ onOK();
+ }
+ };
+
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.weightx = 1.;
+ btnPanel.add(Box.createHorizontalGlue(), gbc);
+
+ gbc.gridx = Main.isLinuxOrMacOSX() ? 2 : 1;
+ gbc.gridy = 0;
+ gbc.weightx = 0.;
+ btnPanel.add(new JButton(actOK), gbc);
+
+ gbc.gridx = Main.isLinuxOrMacOSX() ? 1 : 2;
+ gbc.gridy = 0;
+ gbc.weightx = 0.;
+ btnPanel.add(new JButton(actClose), gbc);
+
+ // ダイアログ下部
+ JPanel southPanel = new JPanel(new BorderLayout());
+ southPanel.add(authorPanel, BorderLayout.NORTH);
+ southPanel.add(btnPanel, BorderLayout.SOUTH);
+
+ contentPane.add(southPanel, BorderLayout.SOUTH);
+
+ // キーボード
+
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ JRootPane rootPane = getRootPane();
+ InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ ActionMap am = rootPane.getActionMap();
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closePartsManageDialog");
+ im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "closePartsManageDialog");
+ am.put("closePartsManageDialog", actClose);
+
+ // モデル構築
+ partsManageTableModel.initModel(characterData);
+
+ // ウィンドウ配置
+ setSize(500, 400);
+ setLocationRelativeTo(parent);
+ }
+
+ private Semaphore authorEditSemaphore = new Semaphore(1);
+
+ protected void onChangeSelection() {
+ try {
+ authorEditSemaphore.acquire();
+ try {
+ int [] selRows = partsManageTable.getSelectedRows();
+ HashSet<String> authors = new HashSet<String>();
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ authors.add(row.getAuthor() == null ? "" : row.getAuthor());
+ }
+ if (authors.size() > 1) {
+ AppConfig appConfig = AppConfig.getInstance();
+ txtAuthor.setBackground(appConfig.getAuthorEditConflictBgColor());
+ txtHomepage.setBackground(appConfig.getAuthorEditConflictBgColor());
+ } else {
+ Color bgColor = UIManager.getColor("TextField.background");
+ if (bgColor == null) {
+ bgColor = Color.white;
+ }
+ txtAuthor.setBackground(bgColor);
+ txtHomepage.setBackground(bgColor);
+ }
+ if (authors.isEmpty()) {
+ // 選択されているauthorがない場合は全部編集不可
+ txtAuthor.setEditable(false);
+ txtAuthor.setText("");
+ txtHomepage.setEditable(false);
+ txtHomepage.setText("");
+ } else {
+ // 選択されているAuthorが1つ以上あればAuthorは編集可
+ txtAuthor.setEditable(true);
+ txtHomepage.setEditable(true);
+ if (authors.size() == 1) {
+ // 選択されているAuthorが一個であれば、それを表示
+ String author = authors.iterator().next();
+ String homepage = partsManageTableModel.getHomepage(author);
+ txtAuthor.setText(author);
+ txtHomepage.setText(homepage);
+ } else {
+ // 選択されているAuthorが二個以上あれば編集可能だがテキストには表示しない.
+ txtAuthor.setText("");
+ txtHomepage.setText("");
+ }
+ }
+ } finally {
+ authorEditSemaphore.release();
+ }
+
+ } catch (InterruptedException ex) {
+ ErrorMessageHelper.showErrorDialog(this, ex);
+
+ } catch (RuntimeException ex) {
+ ErrorMessageHelper.showErrorDialog(this, ex);
+ }
+ }
+
+ protected void onTableDataChange(int firstRow, int lastRow) {
+ onChangeSelection();
+ }
+
+ protected void onApplyAllLastModified() {
+ int[] selRows = partsManageTable.getSelectedRows();
+ if (selRows.length == 0) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ tk.beep();
+ return;
+ }
+ Arrays.sort(selRows);
+
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ Timestamp dt = row.getTimestamp();
+ row.setLastModified(dt);
+ }
+ partsManageTableModel.fireTableRowsUpdated(selRows[0],
+ selRows[selRows.length - 1]);
+ }
+
+ protected void onApplyAllDownloadURL() {
+ int[] selRows = partsManageTable.getSelectedRows();
+ if (selRows.length == 0) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ tk.beep();
+ return;
+ }
+ Arrays.sort(selRows);
+
+ HashSet<String> authors = new HashSet<String>();
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ authors.add(row.getAuthor() == null ? "" : row.getAuthor());
+ }
+
+ Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
+ .getLocalizedProperties(STRINGS_RESOURCE);
+
+ if (authors.size() > 1) {
+ if (JOptionPane.showConfirmDialog(this,
+ strings.getProperty("confirm.authorConflict"),
+ strings.getProperty("confirm"),
+ JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ }
+
+ PartsManageTableRow firstRow = partsManageTableModel.getRow(selRows[0]);
+ String downloadURL = firstRow.getDownloadURL();
+ if (downloadURL == null) {
+ downloadURL = "";
+ }
+ String downloadURL_new = JOptionPane.showInputDialog(this, strings.getProperty("input.downloadURL"), downloadURL);
+ if (downloadURL_new == null || downloadURL.equals(downloadURL_new)) {
+ // キャンセルされたか、内容に変化ない場合は何もしない
+ return;
+ }
+
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ row.setDownloadURL(downloadURL_new);
+
+ Timestamp dt = row.getTimestamp();
+ row.setLastModified(dt);
+ }
+ partsManageTableModel.fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);
+ }
+
+ protected void onApplyAllVersion() {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ int[] selRows = partsManageTable.getSelectedRows();
+ if (selRows.length == 0) {
+ tk.beep();
+ return;
+ }
+ Arrays.sort(selRows);
+
+ HashSet<String> authors = new HashSet<String>();
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ authors.add(row.getAuthor() == null ? "" : row.getAuthor());
+ }
+
+ Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
+ .getLocalizedProperties(STRINGS_RESOURCE);
+
+ if (authors.size() > 1) {
+ if (JOptionPane.showConfirmDialog(this,
+ strings.getProperty("confirm.authorConflict"),
+ strings.getProperty("confirm"),
+ JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
+ return;
+ }
+ }
+
+ PartsManageTableRow firstRow = partsManageTableModel.getRow(selRows[0]);
+ double version = firstRow.getVersion();
+ String strVersion = (version < 0) ? "" : Double.toString(version);
+ String strVersion_new = JOptionPane.showInputDialog(this,
+ strings.getProperty("input.version"), strVersion);
+ if (strVersion_new == null || strVersion.equals(strVersion_new)) {
+ // キャンセルされたか、内容に変化ない場合は何もしない
+ return;
+ }
+ double version_new;
+ try {
+ version_new = Double.parseDouble(strVersion_new);
+ } catch (Exception ex) {
+ // 数値として不正であれば何もしない.
+ tk.beep();
+ return;
+ }
+
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ row.setVersion(version_new);
+
+ Timestamp dt = row.getTimestamp();
+ row.setLastModified(dt);
+ }
+ partsManageTableModel.fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);
+ }
+
+ protected void onEditHomepage() {
+ try {
+ if (!authorEditSemaphore.tryAcquire()) {
+ return;
+ }
+ try {
+ String author = txtAuthor.getText();
+ String homepage = txtHomepage.getText();
+ partsManageTableModel.setHomepage(author, homepage);
+ } finally {
+ authorEditSemaphore.release();
+ }
+ } catch (Exception ex) {
+ ErrorMessageHelper.showErrorDialog(this, ex);
+ }
+ }
+
+ protected void onEditAuthor() {
+ try {
+ if (!authorEditSemaphore.tryAcquire()) {
+ return;
+ }
+ try {
+ String author = txtAuthor.getText();
+ int[] selRows = partsManageTable.getSelectedRows();
+ int firstRow = -1;
+ int lastRow = Integer.MAX_VALUE;
+ for (int selRow : selRows) {
+ PartsManageTableRow row = partsManageTableModel.getRow(selRow);
+ String oldValue = row.getAuthor();
+ if (oldValue == null || !oldValue.equals(author)) {
+ row.setAuthor(author);
+
+ Timestamp dt = row.getTimestamp();
+ row.setLastModified(dt);
+
+ firstRow = Math.max(firstRow, selRow);
+ lastRow = Math.min(lastRow, selRow);
+ }
+ }
+
+ String homepage = partsManageTableModel.getHomepage(author);
+ if (homepage == null) {
+ homepage = "";
+ }
+ txtHomepage.setText(homepage);
+
+ if (firstRow >= 0) {
+ partsManageTable.repaint();
+ }
+ } finally {
+ authorEditSemaphore.release();
+ }
+ } catch (Exception ex) {
+ ErrorMessageHelper.showErrorDialog(this, ex);
+ }
+ }
+
+ protected void onClose() {
+ Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
+ .getLocalizedProperties(STRINGS_RESOURCE);
+ if (JOptionPane.showConfirmDialog(this,
+ strings.getProperty("confirm.cancel"),
+ strings.getProperty("confirm"),
+ JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
+ return;
+ }
+ updated = false;
+ dispose();
+ }
+
+ protected void onBrosweHomepage() {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ String homepage = txtHomepage.getText();
+ if (homepage == null || homepage.trim().length() == 0) {
+ tk.beep();
+ return;
+ }
+ try {
+ URI uri = new URI(homepage);
+ DesktopUtilities.browse(uri);
+
+ } catch (Exception ex) {
+ tk.beep();
+ logger.log(Level.INFO, "browse failed. : " + homepage, ex);
+ }
+ }
+
+ protected void onSortByAuthor() {
+ partsManageTableModel.sortByAuthor();
+ }
+
+ protected void onSortByName() {
+ partsManageTableModel.sortByName();
+ }
+
+ protected void onSortByTimestamp() {
+ partsManageTableModel.sortByTimestamp();
+ }
+
+ protected void onOK() {
+ if (partsManageTable.isEditing()) {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ tk.beep();
+ return;
+ }
+
+ int mx = partsManageTableModel.getRowCount();
+
+ // 作者ごとのホームページ情報の取得
+ // (同一作者につきホームページは一つ)
+ HashMap<String, PartsAuthorInfo> authorInfoMap = new HashMap<String, PartsAuthorInfo>();
+ for (int idx = 0; idx < mx; idx++) {
+ PartsManageTableRow row = partsManageTableModel.getRow(idx);
+ String author = row.getAuthor();
+ String homepage = row.getHomepage();
+ if (author != null && author.trim().length() > 0) {
+ PartsAuthorInfo authorInfo = authorInfoMap.get(author.trim());
+ if (authorInfo == null) {
+ authorInfo = new PartsAuthorInfo();
+ authorInfo.setAuthor(author.trim());
+ authorInfoMap.put(authorInfo.getAuthor(), authorInfo);
+ }
+ authorInfo.setHomePage(homepage);
+ }
+ }
+
+ PartsManageData partsManageData = new PartsManageData();
+
+ // パーツごとの作者とバージョン、ダウンロード先の取得
+ for (int idx = 0; idx < mx; idx++) {
+ PartsManageTableRow row = partsManageTableModel.getRow(idx);
+
+ String author = row.getAuthor();
+ PartsAuthorInfo partsAuthorInfo = null;
+ if (author != null && author.trim().length() > 0) {
+ partsAuthorInfo = authorInfoMap.get(author.trim());
+ }
+
+ double version = row.getVersion();
+ String downloadURL = row.getDownloadURL();
+ String localizedName = row.getLocalizedName();
+ Timestamp lastModified = row.getLastModified();
+
+ PartsManageData.PartsVersionInfo versionInfo = new PartsManageData.PartsVersionInfo();
+ versionInfo.setVersion(version);
+ versionInfo.setDownloadURL(downloadURL);
+ versionInfo.setLastModified(lastModified);
+
+ PartsIdentifier partsIdentifier = row.getPartsIdentifier();
+
+ PartsManageData.PartsKey partsKey = new PartsManageData.PartsKey(partsIdentifier);
+ partsManageData.putPartsInfo(partsKey, localizedName,
+ partsAuthorInfo, versionInfo);
+ }
+
+ // パーツ管理情報を書き込む.
+ PartsInfoXMLWriter xmlWriter = new PartsInfoXMLWriter();
+ try {
+ URI docBase = characterData.getDocBase();
+ xmlWriter.savePartsManageData(docBase, partsManageData);
+
+ } catch (Exception ex) {
+ ErrorMessageHelper.showErrorDialog(this, ex);
+ return;
+ }
+
+ updated = true;
+ dispose();
+ }
+
+ /**
+ * パーツ管理情報が更新されたか?
+ *
+ * @return 更新された場合はtrue、そうでなければfalse
+ */
+ public boolean isUpdated() {
+ return updated;
+ }
+}
+
+class PartsManageTableRow {
+
+ private PartsIdentifier partsIdentifier;
+
+ private Timestamp timestamp;
+
+ private String localizedName;
+
+ private String author;
+
+ private String homepage;
+
+ private String downloadURL;
+
+ private double version;
+
+ private Timestamp lastModified;
+
+ public PartsManageTableRow(PartsIdentifier partsIdentifier,
+ PartsSpec partsSpec, Timestamp lastModified) {
+ if (partsIdentifier == null || partsSpec == null) {
+ throw new IllegalArgumentException();
+ }
+ this.partsIdentifier = partsIdentifier;
+ this.localizedName = partsIdentifier.getLocalizedPartsName();
+
+ this.timestamp = new Timestamp(partsSpec.getPartsFiles().lastModified());
+
+ this.lastModified = lastModified;
+
+ PartsAuthorInfo autherInfo = partsSpec.getAuthorInfo();
+ if (autherInfo != null) {
+ author = autherInfo.getAuthor();
+ homepage = autherInfo.getHomePage();
+ }
+ if (author == null) {
+ author = "";
+ }
+ if (homepage == null) {
+ homepage = "";
+ }
+ downloadURL = partsSpec.getDownloadURL();
+ version = partsSpec.getVersion();
+ }
+
+ public PartsIdentifier getPartsIdentifier() {
+ return partsIdentifier;
+ }
+
+ public Timestamp getTimestamp() {
+ return timestamp;
+ }
+
+ public String getLocalizedName() {
+ return localizedName;
+ }
+
+ public void setLocalizedName(String localizedName) {
+ if (localizedName == null || localizedName.trim().length() == 0) {
+ throw new IllegalArgumentException();
+ }
+ this.localizedName = localizedName;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public String getDownloadURL() {
+ return downloadURL;
+ }
+
+ public double getVersion() {
+ return version;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public void setDownloadURL(String downloadURL) {
+ this.downloadURL = downloadURL;
+ }
+
+ public void setVersion(double version) {
+ this.version = version;
+ }
+
+ public String getHomepage() {
+ return homepage;
+ }
+
+ public void setHomepage(String homepage) {
+ this.homepage = homepage;
+ }
+
+ public Timestamp getLastModified() {
+ return lastModified;
+ }
+
+ public void setLastModified(Timestamp lastModified) {
+ this.lastModified = lastModified;
+ }
+}
+
+class PartsManageTableModel extends AbstractTableModelWithComboBoxModel<PartsManageTableRow> {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger logger = Logger
+ .getLogger(PartsManageTableModel.class.getName());
+
+ private static Properties strings = LocalizedResourcePropertyLoader
+ .getCachedInstance().getLocalizedProperties(
+ PartsManageDialog.STRINGS_RESOURCE);
+
+ /**
+ * カラムの定義
+ */
+ public enum Columns {
+ PartsID("column.partsid", false, String.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getPartsIdentifier().getPartsName();
+ }
+ },
+ LastModified("column.lastmodified", false, String.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getTimestamp().toString();
+ }
+ },
+ Category("column.category", false, String.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getPartsIdentifier().getPartsCategory()
+ .getLocalizedCategoryName();
+ }
+ },
+ PartsName("column.partsname", true, String.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getLocalizedName();
+ }
+ @Override
+ public void setValue(PartsManageTableRow row, Object value) {
+ String localizedName = (String) value;
+ if (localizedName != null && localizedName.trim().length() > 0) {
+ String oldValue = row.getLocalizedName();
+ if (oldValue != null && oldValue.equals(localizedName)) {
+ return; // 変化なし
+ }
+ row.setLocalizedName(localizedName);
+ }
+ }
+ },
+ Author("column.author", true, String.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getAuthor();
+ }
+ @Override
+ public void setValue(PartsManageTableRow row, Object value) {
+ String author = (String) value;
+ if (author == null) {
+ author = "";
+ }
+ String oldValue = row.getAuthor();
+ if (oldValue != null && oldValue.equals(author)) {
+ return; // 変化なし
+ }
+ row.setAuthor(author);
+ }
+ },
+ Version("column.version", true, Double.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getVersion() > 0 ? row.getVersion() : null;
+ }
+ @Override
+ public void setValue(PartsManageTableRow row, Object value) {
+ Double version = (Double) value;
+ if (version == null || version.doubleValue() <= 0) {
+ version = Double.valueOf(0.);
+ }
+ Double oldValue = row.getVersion();
+ if (oldValue != null && oldValue.equals(version)) {
+ return; // 変化なし
+ }
+ row.setVersion(version);
+ }
+ },
+ DownloadURL("column.downloadURL", true, String.class) {
+ @Override
+ public Object getValue(PartsManageTableRow row) {
+ return row.getDownloadURL();
+ }
+ @Override
+ public void setValue(PartsManageTableRow row, Object value) {
+ String downloadURL = (String) value;
+ if (downloadURL == null) {
+ downloadURL = "";
+ }
+ String oldValue = row.getDownloadURL();
+ if (oldValue != null && oldValue.equals(downloadURL)) {
+ return; // 変化なし
+ }
+ row.setDownloadURL(downloadURL);
+ }
+ };
+
+ private final Class<?> columnClass;
+
+ private final boolean editable;
+
+ private final String columnName;
+
+ private String displayName;
+
+ private int width;
+
+ private Columns(String columnName, boolean editable,
+ Class<?> columnClass) {
+ this.columnName = columnName;
+ this.editable = editable;
+ this.columnClass = columnClass;
+ }
+
+ public abstract Object getValue(PartsManageTableRow row);
+
+ public boolean isEditable() {
+ return editable;
+ }
+
+ public Class<?> getColumnClass() {
+ return columnClass;
+ }
+
+ public String getDisplayName() {
+ init();
+ return displayName;
+ }
+
+ public int getWidth() {
+ init();
+ return width;
+ }
+
+ public void setValue(PartsManageTableRow row, Object value) {
+ // 何もしない.
+ }
+
+ private void init() {
+ if (displayName != null) {
+ return;
+ }
+ displayName = strings.getProperty(columnName);
+ width = Integer
+ .parseInt(strings.getProperty(columnName + ".width"));
+ }
+ }
+
+
+ public int getColumnCount() {
+ return Columns.values().length;
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return Columns.values()[column].getDisplayName();
+ }
+
+ public void adjustColumnModel(TableColumnModel columnModel) {
+ Columns[] columns = Columns.values();
+ for (int idx = 0; idx < columns.length; idx++) {
+ columnModel.getColumn(idx).setPreferredWidth(
+ columns[idx].getWidth());
+ }
+ }
+
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ PartsManageTableRow row = getRow(rowIndex);
+ Columns column = Columns.values()[columnIndex];
+ return column.getValue(row);
+ }
+
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ PartsManageTableRow row = getRow(rowIndex);
+ Columns column = Columns.values()[columnIndex];
+ if (!column.isEditable()) {
+ return;
+ }
+ column.setValue(row, aValue);
+
+ // 更新日を最新にする
+ Timestamp dt = row.getTimestamp();
+ row.setLastModified(dt);
+
+ // 変更通知
+ fireTableRowsUpdated(rowIndex, columnIndex);
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ Columns column = Columns.values()[columnIndex];
+ return column.getColumnClass();
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ Columns column = Columns.values()[columnIndex];
+ return column.isEditable();
+ }
+
+ public void initModel(CharacterData characterData) {
+ if (characterData == null) {
+ throw new IllegalArgumentException();
+ }
+ clear();
+
+ // 既存のパーツ管理情報ファイルがあれば読み込む
+ URI docBase = characterData.getDocBase();
+ PartsManageData partsManageData = null;
+ if (docBase != null) {
+ try {
+ PartsInfoXMLReader reader = new PartsInfoXMLReader();
+ partsManageData = reader.loadPartsManageData(docBase);
+
+ } catch (Exception ex) {
+ logger.log(Level.WARNING, ex.toString(), ex);
+ }
+ }
+ if (partsManageData == null) {
+ partsManageData = new PartsManageData();
+ }
+
+ for (PartsCategory partsCategory : characterData.getPartsCategories()) {
+ for (Map.Entry<PartsIdentifier, PartsSpec> entry : characterData
+ .getPartsSpecMap(partsCategory).entrySet()) {
+ PartsIdentifier partsIdentifier = entry.getKey();
+ PartsSpec partsSpec = entry.getValue();
+
+ // パーツ管理情報ファイルから、パーツ管理情報を設定した時点の
+ // ファイルサイズや更新日時などを読み取る.
+ PartsKey partsKey = new PartsKey(partsIdentifier);
+ PartsVersionInfo versionInfo = partsManageData
+ .getVersion(partsKey);
+
+ Timestamp lastModified = null;
+
+ if (versionInfo != null) {
+ lastModified = versionInfo.getLastModified();
+ }
+
+ PartsManageTableRow row = new PartsManageTableRow(
+ partsIdentifier, partsSpec, lastModified);
+ addRow(row);
+ }
+ }
+
+ sortByAuthor();
+ }
+
+ /**
+ * ホームページを設定する.<br>
+ * ホームページはAuthorに対して1つであるが、Authorが自由編集可能であるため便宜的にRowに持たせている.<br>
+ * 結果として同じAuthorに対して同じ値を設定する必要がある.<br>
+ * ホームページはテーブルに表示されないのでリスナーへの通知は行わない.<br>
+ *
+ * @param author
+ * 作者、空またはnullは何もしない.
+ * @param homepage
+ * ホームページ
+ */
+ public void setHomepage(String author, String homepage) {
+ if (author == null || author.length() == 0) {
+ return;
+ }
+ for (PartsManageTableRow row : elements) {
+ String targetAuthor = row.getAuthor();
+ if (targetAuthor == null) {
+ targetAuthor = "";
+ }
+ if (targetAuthor.equals(author)) {
+ row.setHomepage(homepage);
+ }
+ }
+ }
+
+ /**
+ * ホームページを取得する.<br>
+ * 該当する作者がないか、作者がnullまたは空の場合は常にnullを返す.<br>
+ *
+ * @param author
+ * 作者
+ * @return ホームページ、またはnull
+ */
+ public String getHomepage(String author) {
+ if (author == null || author.length() == 0) {
+ return null;
+ }
+ for (PartsManageTableRow row : elements) {
+ String targetAuthor = row.getAuthor();
+ if (targetAuthor == null) {
+ targetAuthor = "";
+ }
+ if (targetAuthor.equals(author)) {
+ return row.getHomepage();
+ }
+ }
+ return null;
+ }
+
+ protected static final Comparator<PartsManageTableRow> NAMED_SORTER
+ = new Comparator<PartsManageTableRow>() {
+ public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {
+ // カテゴリで順序づけ
+ int ret = o1.getPartsIdentifier().getPartsCategory().compareTo(
+ o2.getPartsIdentifier().getPartsCategory());
+ if (ret == 0) {
+ // 表示名で順序づけ
+ String lnm1 = o1.getLocalizedName();
+ String lnm2 = o2.getLocalizedName();
+ if (lnm1 == null) {
+ lnm1 = "";
+ }
+ if (lnm2 == null) {
+ lnm2 = "";
+ }
+ ret = lnm1.compareTo(lnm2);
+ }
+ if (ret == 0) {
+ // それでも判定できなければ元の識別子で判定する.
+ ret = o1.getPartsIdentifier().compareTo(o2.getPartsIdentifier());
+ }
+ return ret;
+ }
+ };
+
+ public void sortByName() {
+ Collections.sort(elements, NAMED_SORTER);
+ fireTableDataChanged();
+ }
+
+ public void sortByTimestamp() {
+ Collections.sort(elements, new Comparator<PartsManageTableRow>() {
+ public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {
+ // 更新日で順序づけ (新しいもの順)
+ int ret = o1.getTimestamp().compareTo(o2.getTimestamp()) * -1;
+ if (ret == 0) {
+ // それでも判定できなければ名前順と同じ
+ ret = NAMED_SORTER.compare(o1, o2);
+ }
+ return ret;
+ }
+ });
+ fireTableDataChanged();
+ }
+
+ public void sortByAuthor() {
+ Collections.sort(elements, new Comparator<PartsManageTableRow>() {
+ public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {
+ // 作者で順序づけ
+ String author1 = o1.getAuthor();
+ String author2 = o2.getAuthor();
+ if (author1 == null) {
+ author1 = "";
+ }
+ if (author2 == null) {
+ author2 = "";
+ }
+ int ret = author1.compareTo(author2);
+ if (ret == 0) {
+ // それでも判定できなければ名前順と同じ
+ ret = NAMED_SORTER.compare(o1, o2);
+ }
+ return ret;
+ }
+ });
+ fireTableDataChanged();
+ }
+}