1 package charactermanaj.ui;
3 import java.awt.BorderLayout;
5 import java.awt.Component;
6 import java.awt.Container;
7 import java.awt.GridBagConstraints;
8 import java.awt.GridBagLayout;
9 import java.awt.Insets;
10 import java.awt.Toolkit;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.KeyEvent;
13 import java.awt.event.WindowAdapter;
14 import java.awt.event.WindowEvent;
16 import java.sql.Timestamp;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.Comparator;
20 import java.util.HashMap;
21 import java.util.HashSet;
23 import java.util.Properties;
24 import java.util.concurrent.Semaphore;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
28 import javax.swing.AbstractAction;
29 import javax.swing.Action;
30 import javax.swing.ActionMap;
31 import javax.swing.BorderFactory;
32 import javax.swing.Box;
33 import javax.swing.InputMap;
34 import javax.swing.JButton;
35 import javax.swing.JComponent;
36 import javax.swing.JDialog;
37 import javax.swing.JFrame;
38 import javax.swing.JLabel;
39 import javax.swing.JOptionPane;
40 import javax.swing.JPanel;
41 import javax.swing.JPopupMenu;
42 import javax.swing.JRootPane;
43 import javax.swing.JScrollPane;
44 import javax.swing.JSeparator;
45 import javax.swing.JTable;
46 import javax.swing.JTextField;
47 import javax.swing.KeyStroke;
48 import javax.swing.UIManager;
49 import javax.swing.event.DocumentEvent;
50 import javax.swing.event.DocumentListener;
51 import javax.swing.event.ListSelectionEvent;
52 import javax.swing.event.ListSelectionListener;
53 import javax.swing.event.TableModelEvent;
54 import javax.swing.event.TableModelListener;
55 import javax.swing.table.TableCellRenderer;
56 import javax.swing.table.TableColumnModel;
58 import charactermanaj.Main;
59 import charactermanaj.model.AppConfig;
60 import charactermanaj.model.CharacterData;
61 import charactermanaj.model.PartsAuthorInfo;
62 import charactermanaj.model.PartsCategory;
63 import charactermanaj.model.PartsIdentifier;
64 import charactermanaj.model.PartsManageData;
65 import charactermanaj.model.PartsManageData.PartsKey;
66 import charactermanaj.model.PartsManageData.PartsVersionInfo;
67 import charactermanaj.model.PartsSpec;
68 import charactermanaj.model.io.PartsInfoXMLReader;
69 import charactermanaj.model.io.PartsInfoXMLWriter;
70 import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;
71 import charactermanaj.util.DesktopUtilities;
72 import charactermanaj.util.ErrorMessageHelper;
73 import charactermanaj.util.LocalizedResourcePropertyLoader;
75 public class PartsManageDialog extends JDialog {
77 private static final long serialVersionUID = 1L;
79 protected static final String STRINGS_RESOURCE = "languages/partsmanagedialog";
82 private static final Logger logger = Logger.getLogger(PartsManageDialog.class.getName());
84 private CharacterData characterData;
86 private PartsManageTableModel partsManageTableModel;
88 private JTable partsManageTable;
90 private JTextField txtHomepage;
92 private JTextField txtAuthor;
94 private boolean updated;
97 public PartsManageDialog(JFrame parent, CharacterData characterData) {
100 if (characterData == null) {
101 throw new IllegalArgumentException();
103 this.characterData = characterData;
105 setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
106 addWindowListener(new WindowAdapter() {
108 public void windowClosing(WindowEvent e) {
113 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
114 .getLocalizedProperties(STRINGS_RESOURCE);
116 setTitle(strings.getProperty("title"));
118 Container contentPane = getContentPane();
121 JPanel partsListPanel = new JPanel();
122 partsListPanel.setBorder(BorderFactory.createCompoundBorder(
123 BorderFactory.createEmptyBorder(5, 5, 5, 5), BorderFactory
124 .createTitledBorder(strings.getProperty("partslist"))));
126 GridBagLayout partsListPanelLayout = new GridBagLayout();
127 partsListPanel.setLayout(partsListPanelLayout);
129 partsManageTableModel = new PartsManageTableModel();
130 partsManageTable = new JTable(partsManageTableModel) {
131 private static final long serialVersionUID = 1L;
134 public Component prepareRenderer(TableCellRenderer renderer,
135 int rowIdx, int columnIdx) {
136 PartsManageTableModel.Columns column = PartsManageTableModel.Columns
137 .values()[columnIdx];
138 Component comp = super.prepareRenderer(renderer, rowIdx, columnIdx);
139 PartsManageTableRow row = partsManageTableModel.getRow(rowIdx);
141 Timestamp current = row.getTimestamp();
142 Timestamp lastModified = row.getLastModified();
144 boolean warnings = false;
146 if (current != null && !current.equals(lastModified)) {
147 // 現在のパーツの最終更新日と、パーツ管理情報の作成時のパーツの最終更新日が不一致の場合
152 if (warnings && column == PartsManageTableModel.Columns.LastModified) {
153 AppConfig appConfig = AppConfig.getInstance();
154 Color invalidBgColor = appConfig.getInvalidBgColor();
155 comp.setBackground(invalidBgColor);
157 if (isCellSelected(rowIdx, columnIdx)) {
158 comp.setBackground(getSelectionBackground());
160 comp.setBackground(getBackground());
167 partsManageTable.setShowGrid(true);
168 partsManageTable.setGridColor(AppConfig.getInstance().getGridColor());
169 partsManageTableModel.adjustColumnModel(partsManageTable.getColumnModel());
170 partsManageTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
171 partsManageTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
173 JScrollPane partsManageTableSP = new JScrollPane(partsManageTable);
175 partsManageTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
176 public void valueChanged(ListSelectionEvent e) {
177 if (!e.getValueIsAdjusting()) {
183 partsManageTableModel.addTableModelListener(new TableModelListener() {
184 public void tableChanged(TableModelEvent e) {
185 onTableDataChange(e.getFirstRow(), e.getLastRow());
189 GridBagConstraints gbc = new GridBagConstraints();
194 gbc.anchor = GridBagConstraints.EAST;
195 gbc.fill = GridBagConstraints.BOTH;
196 gbc.insets = new Insets(3, 3, 3, 3);
201 partsListPanel.add(partsManageTableSP, gbc);
203 Action actSortByName = new AbstractAction(strings.getProperty("sortByName")) {
204 private static final long serialVersionUID = 1L;
205 public void actionPerformed(ActionEvent e) {
209 Action actSortByAuthor = new AbstractAction(strings.getProperty("sortByAuthor")) {
210 private static final long serialVersionUID = 1L;
211 public void actionPerformed(ActionEvent e) {
215 Action actSortByTimestamp = new AbstractAction(strings.getProperty("sortByTimestamp")) {
216 private static final long serialVersionUID = 1L;
217 public void actionPerformed(ActionEvent e) {
228 partsListPanel.add(new JButton(actSortByName), gbc);
234 partsListPanel.add(new JButton(actSortByAuthor), gbc);
240 partsListPanel.add(new JButton(actSortByTimestamp), gbc);
246 partsListPanel.add(Box.createHorizontalGlue(), gbc);
248 contentPane.add(partsListPanel, BorderLayout.CENTER);
251 final JPopupMenu popupMenu = new JPopupMenu();
252 Action actApplyAllLastModified = new AbstractAction(strings.getProperty("applyAllLastModified")) {
253 private static final long serialVersionUID = 1L;
254 public void actionPerformed(ActionEvent e) {
255 onApplyAllLastModified();
258 Action actApplyAllDownloadURL = new AbstractAction(strings.getProperty("applyAllDownloadURL")) {
259 private static final long serialVersionUID = 1L;
260 public void actionPerformed(ActionEvent e) {
261 onApplyAllDownloadURL();
264 Action actApplyAllVersion = new AbstractAction(strings.getProperty("applyAllVersion")) {
265 private static final long serialVersionUID = 1L;
266 public void actionPerformed(ActionEvent e) {
270 popupMenu.add(actApplyAllLastModified);
271 popupMenu.add(new JSeparator());
272 popupMenu.add(actApplyAllVersion);
273 popupMenu.add(actApplyAllDownloadURL);
275 partsManageTable.setComponentPopupMenu(popupMenu);
278 JPanel authorPanel = new JPanel();
279 authorPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory
280 .createEmptyBorder(5, 5, 5, 5), BorderFactory
281 .createTitledBorder(strings.getProperty("author.info"))));
282 GridBagLayout authorPanelLayout = new GridBagLayout();
283 authorPanel.setLayout(authorPanelLayout);
289 gbc.anchor = GridBagConstraints.EAST;
290 gbc.fill = GridBagConstraints.BOTH;
291 gbc.insets = new Insets(3, 3, 3, 3);
296 authorPanel.add(new JLabel(strings.getProperty("author"), JLabel.RIGHT), gbc);
302 txtAuthor = new JTextField();
303 authorPanel.add(txtAuthor, gbc);
309 authorPanel.add(new JLabel(strings.getProperty("homepage"), JLabel.RIGHT), gbc);
315 txtHomepage = new JTextField();
316 authorPanel.add(txtHomepage, gbc);
322 Action actBrowseHomepage = new AbstractAction(strings.getProperty("open")) {
323 private static final long serialVersionUID = 1L;
324 public void actionPerformed(ActionEvent e) {
328 authorPanel.add(new JButton(actBrowseHomepage), gbc);
330 if (!DesktopUtilities.isSupported()) {
331 actBrowseHomepage.setEnabled(false);
334 txtAuthor.getDocument().addDocumentListener(new DocumentListener() {
335 public void removeUpdate(DocumentEvent e) {
338 public void insertUpdate(DocumentEvent e) {
341 public void changedUpdate(DocumentEvent e) {
345 txtHomepage.getDocument().addDocumentListener(new DocumentListener() {
346 public void removeUpdate(DocumentEvent e) {
349 public void insertUpdate(DocumentEvent e) {
352 public void changedUpdate(DocumentEvent e) {
359 JPanel btnPanel = new JPanel();
360 btnPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 45));
361 GridBagLayout btnPanelLayout = new GridBagLayout();
362 btnPanel.setLayout(btnPanelLayout);
364 Action actClose = new AbstractAction(strings.getProperty("cancel")) {
365 private static final long serialVersionUID = 1L;
366 public void actionPerformed(ActionEvent e) {
370 Action actOK = new AbstractAction(strings.getProperty("update")) {
371 private static final long serialVersionUID = 1L;
372 public void actionPerformed(ActionEvent e) {
380 btnPanel.add(Box.createHorizontalGlue(), gbc);
382 gbc.gridx = Main.isLinuxOrMacOSX() ? 2 : 1;
385 btnPanel.add(new JButton(actOK), gbc);
387 gbc.gridx = Main.isLinuxOrMacOSX() ? 1 : 2;
390 btnPanel.add(new JButton(actClose), gbc);
393 JPanel southPanel = new JPanel(new BorderLayout());
394 southPanel.add(authorPanel, BorderLayout.NORTH);
395 southPanel.add(btnPanel, BorderLayout.SOUTH);
397 contentPane.add(southPanel, BorderLayout.SOUTH);
401 Toolkit tk = Toolkit.getDefaultToolkit();
402 JRootPane rootPane = getRootPane();
403 InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
404 ActionMap am = rootPane.getActionMap();
405 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closePartsManageDialog");
406 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "closePartsManageDialog");
407 am.put("closePartsManageDialog", actClose);
410 partsManageTableModel.initModel(characterData);
414 setLocationRelativeTo(parent);
417 private Semaphore authorEditSemaphore = new Semaphore(1);
419 protected void onChangeSelection() {
421 authorEditSemaphore.acquire();
423 int [] selRows = partsManageTable.getSelectedRows();
424 HashSet<String> authors = new HashSet<String>();
425 for (int selRow : selRows) {
426 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
427 authors.add(row.getAuthor() == null ? "" : row.getAuthor());
429 if (authors.size() > 1) {
430 AppConfig appConfig = AppConfig.getInstance();
431 txtAuthor.setBackground(appConfig.getAuthorEditConflictBgColor());
432 txtHomepage.setBackground(appConfig.getAuthorEditConflictBgColor());
434 Color bgColor = UIManager.getColor("TextField.background");
435 if (bgColor == null) {
436 bgColor = Color.white;
438 txtAuthor.setBackground(bgColor);
439 txtHomepage.setBackground(bgColor);
441 if (authors.isEmpty()) {
442 // 選択されているauthorがない場合は全部編集不可
443 txtAuthor.setEditable(false);
444 txtAuthor.setText("");
445 txtHomepage.setEditable(false);
446 txtHomepage.setText("");
448 // 選択されているAuthorが1つ以上あればAuthorは編集可
449 txtAuthor.setEditable(true);
450 txtHomepage.setEditable(true);
451 if (authors.size() == 1) {
452 // 選択されているAuthorが一個であれば、それを表示
453 String author = authors.iterator().next();
454 String homepage = partsManageTableModel.getHomepage(author);
455 txtAuthor.setText(author);
456 txtHomepage.setText(homepage);
458 // 選択されているAuthorが二個以上あれば編集可能だがテキストには表示しない.
459 txtAuthor.setText("");
460 txtHomepage.setText("");
464 authorEditSemaphore.release();
467 } catch (InterruptedException ex) {
468 ErrorMessageHelper.showErrorDialog(this, ex);
470 } catch (RuntimeException ex) {
471 ErrorMessageHelper.showErrorDialog(this, ex);
475 protected void onTableDataChange(int firstRow, int lastRow) {
479 protected void onApplyAllLastModified() {
480 int[] selRows = partsManageTable.getSelectedRows();
481 if (selRows.length == 0) {
482 Toolkit tk = Toolkit.getDefaultToolkit();
486 Arrays.sort(selRows);
488 for (int selRow : selRows) {
489 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
490 Timestamp dt = row.getTimestamp();
491 row.setLastModified(dt);
493 partsManageTableModel.fireTableRowsUpdated(selRows[0],
494 selRows[selRows.length - 1]);
497 protected void onApplyAllDownloadURL() {
498 int[] selRows = partsManageTable.getSelectedRows();
499 if (selRows.length == 0) {
500 Toolkit tk = Toolkit.getDefaultToolkit();
504 Arrays.sort(selRows);
506 HashSet<String> authors = new HashSet<String>();
507 for (int selRow : selRows) {
508 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
509 authors.add(row.getAuthor() == null ? "" : row.getAuthor());
512 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
513 .getLocalizedProperties(STRINGS_RESOURCE);
515 if (authors.size() > 1) {
516 if (JOptionPane.showConfirmDialog(this,
517 strings.getProperty("confirm.authorConflict"),
518 strings.getProperty("confirm"),
519 JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
524 PartsManageTableRow firstRow = partsManageTableModel.getRow(selRows[0]);
525 String downloadURL = firstRow.getDownloadURL();
526 if (downloadURL == null) {
529 String downloadURL_new = JOptionPane.showInputDialog(this, strings.getProperty("input.downloadURL"), downloadURL);
530 if (downloadURL_new == null || downloadURL.equals(downloadURL_new)) {
531 // キャンセルされたか、内容に変化ない場合は何もしない
535 for (int selRow : selRows) {
536 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
537 row.setDownloadURL(downloadURL_new);
539 Timestamp dt = row.getTimestamp();
540 row.setLastModified(dt);
542 partsManageTableModel.fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);
545 protected void onApplyAllVersion() {
546 Toolkit tk = Toolkit.getDefaultToolkit();
547 int[] selRows = partsManageTable.getSelectedRows();
548 if (selRows.length == 0) {
552 Arrays.sort(selRows);
554 HashSet<String> authors = new HashSet<String>();
555 for (int selRow : selRows) {
556 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
557 authors.add(row.getAuthor() == null ? "" : row.getAuthor());
560 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
561 .getLocalizedProperties(STRINGS_RESOURCE);
563 if (authors.size() > 1) {
564 if (JOptionPane.showConfirmDialog(this,
565 strings.getProperty("confirm.authorConflict"),
566 strings.getProperty("confirm"),
567 JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
572 PartsManageTableRow firstRow = partsManageTableModel.getRow(selRows[0]);
573 double version = firstRow.getVersion();
574 String strVersion = (version < 0) ? "" : Double.toString(version);
575 String strVersion_new = JOptionPane.showInputDialog(this,
576 strings.getProperty("input.version"), strVersion);
577 if (strVersion_new == null || strVersion.equals(strVersion_new)) {
578 // キャンセルされたか、内容に変化ない場合は何もしない
583 version_new = Double.parseDouble(strVersion_new);
584 } catch (Exception ex) {
590 for (int selRow : selRows) {
591 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
592 row.setVersion(version_new);
594 Timestamp dt = row.getTimestamp();
595 row.setLastModified(dt);
597 partsManageTableModel.fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);
600 protected void onEditHomepage() {
602 if (!authorEditSemaphore.tryAcquire()) {
606 String author = txtAuthor.getText();
607 String homepage = txtHomepage.getText();
608 partsManageTableModel.setHomepage(author, homepage);
610 authorEditSemaphore.release();
612 } catch (Exception ex) {
613 ErrorMessageHelper.showErrorDialog(this, ex);
617 protected void onEditAuthor() {
619 if (!authorEditSemaphore.tryAcquire()) {
623 String author = txtAuthor.getText();
624 int[] selRows = partsManageTable.getSelectedRows();
626 int lastRow = Integer.MAX_VALUE;
627 for (int selRow : selRows) {
628 PartsManageTableRow row = partsManageTableModel.getRow(selRow);
629 String oldValue = row.getAuthor();
630 if (oldValue == null || !oldValue.equals(author)) {
631 row.setAuthor(author);
633 Timestamp dt = row.getTimestamp();
634 row.setLastModified(dt);
636 firstRow = Math.max(firstRow, selRow);
637 lastRow = Math.min(lastRow, selRow);
641 String homepage = partsManageTableModel.getHomepage(author);
642 if (homepage == null) {
645 txtHomepage.setText(homepage);
648 partsManageTable.repaint();
651 authorEditSemaphore.release();
653 } catch (Exception ex) {
654 ErrorMessageHelper.showErrorDialog(this, ex);
658 protected void onClose() {
659 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
660 .getLocalizedProperties(STRINGS_RESOURCE);
661 if (JOptionPane.showConfirmDialog(this,
662 strings.getProperty("confirm.cancel"),
663 strings.getProperty("confirm"),
664 JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
671 protected void onBrosweHomepage() {
672 Toolkit tk = Toolkit.getDefaultToolkit();
673 String homepage = txtHomepage.getText();
674 if (homepage == null || homepage.trim().length() == 0) {
679 URI uri = new URI(homepage);
680 DesktopUtilities.browse(uri);
682 } catch (Exception ex) {
684 logger.log(Level.INFO, "browse failed. : " + homepage, ex);
688 protected void onSortByAuthor() {
689 partsManageTableModel.sortByAuthor();
692 protected void onSortByName() {
693 partsManageTableModel.sortByName();
696 protected void onSortByTimestamp() {
697 partsManageTableModel.sortByTimestamp();
700 protected void onOK() {
701 if (partsManageTable.isEditing()) {
702 Toolkit tk = Toolkit.getDefaultToolkit();
707 int mx = partsManageTableModel.getRowCount();
710 // (同一作者につきホームページは一つ)
711 HashMap<String, PartsAuthorInfo> authorInfoMap = new HashMap<String, PartsAuthorInfo>();
712 for (int idx = 0; idx < mx; idx++) {
713 PartsManageTableRow row = partsManageTableModel.getRow(idx);
714 String author = row.getAuthor();
715 String homepage = row.getHomepage();
716 if (author != null && author.trim().length() > 0) {
717 PartsAuthorInfo authorInfo = authorInfoMap.get(author.trim());
718 if (authorInfo == null) {
719 authorInfo = new PartsAuthorInfo();
720 authorInfo.setAuthor(author.trim());
721 authorInfoMap.put(authorInfo.getAuthor(), authorInfo);
723 authorInfo.setHomePage(homepage);
727 PartsManageData partsManageData = new PartsManageData();
729 // パーツごとの作者とバージョン、ダウンロード先の取得
730 for (int idx = 0; idx < mx; idx++) {
731 PartsManageTableRow row = partsManageTableModel.getRow(idx);
733 String author = row.getAuthor();
734 PartsAuthorInfo partsAuthorInfo = null;
735 if (author != null && author.trim().length() > 0) {
736 partsAuthorInfo = authorInfoMap.get(author.trim());
739 double version = row.getVersion();
740 String downloadURL = row.getDownloadURL();
741 String localizedName = row.getLocalizedName();
742 Timestamp lastModified = row.getLastModified();
744 PartsManageData.PartsVersionInfo versionInfo = new PartsManageData.PartsVersionInfo();
745 versionInfo.setVersion(version);
746 versionInfo.setDownloadURL(downloadURL);
747 versionInfo.setLastModified(lastModified);
749 PartsIdentifier partsIdentifier = row.getPartsIdentifier();
751 PartsManageData.PartsKey partsKey = new PartsManageData.PartsKey(partsIdentifier);
752 partsManageData.putPartsInfo(partsKey, localizedName,
753 partsAuthorInfo, versionInfo);
757 PartsInfoXMLWriter xmlWriter = new PartsInfoXMLWriter();
759 URI docBase = characterData.getDocBase();
760 xmlWriter.savePartsManageData(docBase, partsManageData);
762 } catch (Exception ex) {
763 ErrorMessageHelper.showErrorDialog(this, ex);
774 * @return 更新された場合はtrue、そうでなければfalse
776 public boolean isUpdated() {
781 class PartsManageTableRow {
783 private PartsIdentifier partsIdentifier;
785 private Timestamp timestamp;
787 private String localizedName;
789 private String author;
791 private String homepage;
793 private String downloadURL;
795 private double version;
797 private Timestamp lastModified;
799 public PartsManageTableRow(PartsIdentifier partsIdentifier,
800 PartsSpec partsSpec, Timestamp lastModified) {
801 if (partsIdentifier == null || partsSpec == null) {
802 throw new IllegalArgumentException();
804 this.partsIdentifier = partsIdentifier;
805 this.localizedName = partsIdentifier.getLocalizedPartsName();
807 this.timestamp = new Timestamp(partsSpec.getPartsFiles().lastModified());
809 this.lastModified = lastModified;
811 PartsAuthorInfo autherInfo = partsSpec.getAuthorInfo();
812 if (autherInfo != null) {
813 author = autherInfo.getAuthor();
814 homepage = autherInfo.getHomePage();
816 if (author == null) {
819 if (homepage == null) {
822 downloadURL = partsSpec.getDownloadURL();
823 version = partsSpec.getVersion();
826 public PartsIdentifier getPartsIdentifier() {
827 return partsIdentifier;
830 public Timestamp getTimestamp() {
834 public String getLocalizedName() {
835 return localizedName;
838 public void setLocalizedName(String localizedName) {
839 if (localizedName == null || localizedName.trim().length() == 0) {
840 throw new IllegalArgumentException();
842 this.localizedName = localizedName;
845 public String getAuthor() {
849 public String getDownloadURL() {
853 public double getVersion() {
857 public void setAuthor(String author) {
858 this.author = author;
861 public void setDownloadURL(String downloadURL) {
862 this.downloadURL = downloadURL;
865 public void setVersion(double version) {
866 this.version = version;
869 public String getHomepage() {
873 public void setHomepage(String homepage) {
874 this.homepage = homepage;
877 public Timestamp getLastModified() {
881 public void setLastModified(Timestamp lastModified) {
882 this.lastModified = lastModified;
886 class PartsManageTableModel extends AbstractTableModelWithComboBoxModel<PartsManageTableRow> {
888 private static final long serialVersionUID = 1L;
890 private static final Logger logger = Logger
891 .getLogger(PartsManageTableModel.class.getName());
893 private static Properties strings = LocalizedResourcePropertyLoader
894 .getCachedInstance().getLocalizedProperties(
895 PartsManageDialog.STRINGS_RESOURCE);
900 public enum Columns {
901 PartsID("column.partsid", false, String.class) {
903 public Object getValue(PartsManageTableRow row) {
904 return row.getPartsIdentifier().getPartsName();
907 LastModified("column.lastmodified", false, String.class) {
909 public Object getValue(PartsManageTableRow row) {
910 return row.getTimestamp().toString();
913 Category("column.category", false, String.class) {
915 public Object getValue(PartsManageTableRow row) {
916 return row.getPartsIdentifier().getPartsCategory()
917 .getLocalizedCategoryName();
920 PartsName("column.partsname", true, String.class) {
922 public Object getValue(PartsManageTableRow row) {
923 return row.getLocalizedName();
926 public void setValue(PartsManageTableRow row, Object value) {
927 String localizedName = (String) value;
928 if (localizedName != null && localizedName.trim().length() > 0) {
929 String oldValue = row.getLocalizedName();
930 if (oldValue != null && oldValue.equals(localizedName)) {
933 row.setLocalizedName(localizedName);
937 Author("column.author", true, String.class) {
939 public Object getValue(PartsManageTableRow row) {
940 return row.getAuthor();
943 public void setValue(PartsManageTableRow row, Object value) {
944 String author = (String) value;
945 if (author == null) {
948 String oldValue = row.getAuthor();
949 if (oldValue != null && oldValue.equals(author)) {
952 row.setAuthor(author);
955 Version("column.version", true, Double.class) {
957 public Object getValue(PartsManageTableRow row) {
958 return row.getVersion() > 0 ? row.getVersion() : null;
961 public void setValue(PartsManageTableRow row, Object value) {
962 Double version = (Double) value;
963 if (version == null || version.doubleValue() <= 0) {
964 version = Double.valueOf(0.);
966 Double oldValue = row.getVersion();
967 if (oldValue != null && oldValue.equals(version)) {
970 row.setVersion(version);
973 DownloadURL("column.downloadURL", true, String.class) {
975 public Object getValue(PartsManageTableRow row) {
976 return row.getDownloadURL();
979 public void setValue(PartsManageTableRow row, Object value) {
980 String downloadURL = (String) value;
981 if (downloadURL == null) {
984 String oldValue = row.getDownloadURL();
985 if (oldValue != null && oldValue.equals(downloadURL)) {
988 row.setDownloadURL(downloadURL);
992 private final Class<?> columnClass;
994 private final boolean editable;
996 private final String columnName;
998 private String displayName;
1002 private Columns(String columnName, boolean editable,
1003 Class<?> columnClass) {
1004 this.columnName = columnName;
1005 this.editable = editable;
1006 this.columnClass = columnClass;
1009 public abstract Object getValue(PartsManageTableRow row);
1011 public boolean isEditable() {
1015 public Class<?> getColumnClass() {
1019 public String getDisplayName() {
1024 public int getWidth() {
1029 public void setValue(PartsManageTableRow row, Object value) {
1033 private void init() {
1034 if (displayName != null) {
1037 displayName = strings.getProperty(columnName);
1039 .parseInt(strings.getProperty(columnName + ".width"));
1044 public int getColumnCount() {
1045 return Columns.values().length;
1049 public String getColumnName(int column) {
1050 return Columns.values()[column].getDisplayName();
1053 public void adjustColumnModel(TableColumnModel columnModel) {
1054 Columns[] columns = Columns.values();
1055 for (int idx = 0; idx < columns.length; idx++) {
1056 columnModel.getColumn(idx).setPreferredWidth(
1057 columns[idx].getWidth());
1061 public Object getValueAt(int rowIndex, int columnIndex) {
1062 PartsManageTableRow row = getRow(rowIndex);
1063 Columns column = Columns.values()[columnIndex];
1064 return column.getValue(row);
1068 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
1069 PartsManageTableRow row = getRow(rowIndex);
1070 Columns column = Columns.values()[columnIndex];
1071 if (!column.isEditable()) {
1074 column.setValue(row, aValue);
1077 Timestamp dt = row.getTimestamp();
1078 row.setLastModified(dt);
1081 fireTableRowsUpdated(rowIndex, columnIndex);
1085 public Class<?> getColumnClass(int columnIndex) {
1086 Columns column = Columns.values()[columnIndex];
1087 return column.getColumnClass();
1091 public boolean isCellEditable(int rowIndex, int columnIndex) {
1092 Columns column = Columns.values()[columnIndex];
1093 return column.isEditable();
1096 public void initModel(CharacterData characterData) {
1097 if (characterData == null) {
1098 throw new IllegalArgumentException();
1102 // 既存のパーツ管理情報ファイルがあれば読み込む
1103 URI docBase = characterData.getDocBase();
1104 PartsManageData partsManageData = null;
1105 if (docBase != null) {
1107 PartsInfoXMLReader reader = new PartsInfoXMLReader();
1108 partsManageData = reader.loadPartsManageData(docBase);
1110 } catch (Exception ex) {
1111 logger.log(Level.WARNING, ex.toString(), ex);
1114 if (partsManageData == null) {
1115 partsManageData = new PartsManageData();
1118 for (PartsCategory partsCategory : characterData.getPartsCategories()) {
1119 for (Map.Entry<PartsIdentifier, PartsSpec> entry : characterData
1120 .getPartsSpecMap(partsCategory).entrySet()) {
1121 PartsIdentifier partsIdentifier = entry.getKey();
1122 PartsSpec partsSpec = entry.getValue();
1124 // パーツ管理情報ファイルから、パーツ管理情報を設定した時点の
1125 // ファイルサイズや更新日時などを読み取る.
1126 PartsKey partsKey = new PartsKey(partsIdentifier);
1127 PartsVersionInfo versionInfo = partsManageData
1128 .getVersion(partsKey);
1130 Timestamp lastModified = null;
1132 if (versionInfo != null) {
1133 lastModified = versionInfo.getLastModified();
1136 PartsManageTableRow row = new PartsManageTableRow(
1137 partsIdentifier, partsSpec, lastModified);
1147 * ホームページはAuthorに対して1つであるが、Authorが自由編集可能であるため便宜的にRowに持たせている.<br>
1148 * 結果として同じAuthorに対して同じ値を設定する必要がある.<br>
1149 * ホームページはテーブルに表示されないのでリスナーへの通知は行わない.<br>
1152 * 作者、空またはnullは何もしない.
1156 public void setHomepage(String author, String homepage) {
1157 if (author == null || author.length() == 0) {
1160 for (PartsManageTableRow row : elements) {
1161 String targetAuthor = row.getAuthor();
1162 if (targetAuthor == null) {
1165 if (targetAuthor.equals(author)) {
1166 row.setHomepage(homepage);
1173 * 該当する作者がないか、作者がnullまたは空の場合は常にnullを返す.<br>
1177 * @return ホームページ、またはnull
1179 public String getHomepage(String author) {
1180 if (author == null || author.length() == 0) {
1183 for (PartsManageTableRow row : elements) {
1184 String targetAuthor = row.getAuthor();
1185 if (targetAuthor == null) {
1188 if (targetAuthor.equals(author)) {
1189 return row.getHomepage();
1195 protected static final Comparator<PartsManageTableRow> NAMED_SORTER
1196 = new Comparator<PartsManageTableRow>() {
1197 public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {
1199 int ret = o1.getPartsIdentifier().getPartsCategory().compareTo(
1200 o2.getPartsIdentifier().getPartsCategory());
1203 String lnm1 = o1.getLocalizedName();
1204 String lnm2 = o2.getLocalizedName();
1211 ret = lnm1.compareTo(lnm2);
1214 // それでも判定できなければ元の識別子で判定する.
1215 ret = o1.getPartsIdentifier().compareTo(o2.getPartsIdentifier());
1221 public void sortByName() {
1222 Collections.sort(elements, NAMED_SORTER);
1223 fireTableDataChanged();
1226 public void sortByTimestamp() {
1227 Collections.sort(elements, new Comparator<PartsManageTableRow>() {
1228 public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {
1229 // 更新日で順序づけ (新しいもの順)
1230 int ret = o1.getTimestamp().compareTo(o2.getTimestamp()) * -1;
1232 // それでも判定できなければ名前順と同じ
1233 ret = NAMED_SORTER.compare(o1, o2);
1238 fireTableDataChanged();
1241 public void sortByAuthor() {
1242 Collections.sort(elements, new Comparator<PartsManageTableRow>() {
1243 public int compare(PartsManageTableRow o1, PartsManageTableRow o2) {
1245 String author1 = o1.getAuthor();
1246 String author2 = o2.getAuthor();
1247 if (author1 == null) {
1250 if (author2 == null) {
1253 int ret = author1.compareTo(author2);
1255 // それでも判定できなければ名前順と同じ
1256 ret = NAMED_SORTER.compare(o1, o2);
1261 fireTableDataChanged();