1 package charactermanaj.ui;
3 import java.awt.BorderLayout;
4 import java.awt.CardLayout;
6 import java.awt.Component;
7 import java.awt.Container;
8 import java.awt.Cursor;
9 import java.awt.Dimension;
11 import java.awt.GridBagConstraints;
12 import java.awt.GridBagLayout;
13 import java.awt.Insets;
14 import java.awt.Rectangle;
15 import java.awt.Toolkit;
16 import java.awt.dnd.DropTarget;
17 import java.awt.event.ActionEvent;
18 import java.awt.event.ActionListener;
19 import java.awt.event.ComponentAdapter;
20 import java.awt.event.ComponentEvent;
21 import java.awt.event.ComponentListener;
22 import java.awt.event.KeyEvent;
23 import java.awt.event.WindowAdapter;
24 import java.awt.event.WindowEvent;
25 import java.awt.image.BufferedImage;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
30 import java.sql.Timestamp;
31 import java.text.MessageFormat;
32 import java.util.AbstractCollection;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.IdentityHashMap;
41 import java.util.Iterator;
42 import java.util.LinkedList;
43 import java.util.List;
45 import java.util.Properties;
48 import javax.swing.AbstractAction;
49 import javax.swing.Action;
50 import javax.swing.ActionMap;
51 import javax.swing.BorderFactory;
52 import javax.swing.Box;
53 import javax.swing.BoxLayout;
54 import javax.swing.ButtonGroup;
55 import javax.swing.InputMap;
56 import javax.swing.JButton;
57 import javax.swing.JCheckBox;
58 import javax.swing.JComponent;
59 import javax.swing.JDialog;
60 import javax.swing.JFileChooser;
61 import javax.swing.JFrame;
62 import javax.swing.JLabel;
63 import javax.swing.JOptionPane;
64 import javax.swing.JPanel;
65 import javax.swing.JPopupMenu;
66 import javax.swing.JRadioButton;
67 import javax.swing.JRootPane;
68 import javax.swing.JScrollPane;
69 import javax.swing.JTable;
70 import javax.swing.JTextArea;
71 import javax.swing.JTextField;
72 import javax.swing.KeyStroke;
73 import javax.swing.ListSelectionModel;
74 import javax.swing.event.ChangeEvent;
75 import javax.swing.event.ChangeListener;
76 import javax.swing.event.DocumentEvent;
77 import javax.swing.event.DocumentListener;
78 import javax.swing.event.TableModelEvent;
79 import javax.swing.event.TableModelListener;
80 import javax.swing.table.TableCellRenderer;
81 import javax.swing.table.TableColumnModel;
83 import charactermanaj.Main;
84 import charactermanaj.graphics.io.PNGFileImageHeader;
85 import charactermanaj.model.AppConfig;
86 import charactermanaj.model.CharacterData;
87 import charactermanaj.model.CustomLayerOrder;
88 import charactermanaj.model.CustomLayerOrderKey;
89 import charactermanaj.model.PartsAuthorInfo;
90 import charactermanaj.model.PartsCategory;
91 import charactermanaj.model.PartsIdentifier;
92 import charactermanaj.model.PartsManageData;
93 import charactermanaj.model.PartsSet;
94 import charactermanaj.model.PartsSpec;
95 import charactermanaj.model.io.AbstractCharacterDataArchiveFile.CategoryLayerPair;
96 import charactermanaj.model.io.AbstractCharacterDataArchiveFile.PartsImageContent;
97 import charactermanaj.model.io.CharacterDataFileReaderWriterFactory;
98 import charactermanaj.model.io.CharacterDataPersistent;
99 import charactermanaj.model.io.ImportModel;
100 import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;
101 import charactermanaj.ui.progress.ProgressHandle;
102 import charactermanaj.ui.progress.Worker;
103 import charactermanaj.ui.progress.WorkerException;
104 import charactermanaj.ui.progress.WorkerWithProgessDialog;
105 import charactermanaj.ui.util.FileDropTarget;
106 import charactermanaj.ui.util.ScaleSupport;
107 import charactermanaj.util.DownloadUtils;
108 import charactermanaj.util.DownloadUtils.HeadResponse;
109 import charactermanaj.util.ErrorMessageHelper;
110 import charactermanaj.util.LocalizedResourcePropertyLoader;
114 * インポートウィザードダイアログ.<br>
118 public class ImportWizardDialog extends JDialog {
120 private static final long serialVersionUID = 1L;
123 protected static final String STRINGS_RESOURCE = "languages/importwizdialog";
126 public static final int EXIT_PROFILE_UPDATED = 1;
128 public static final int EXIT_PROFILE_CREATED = 2;
130 public static final int EXIT_CANCELED = 0;
134 * インポートウィザードの実行結果.<br>
136 private int exitCode = EXIT_CANCELED;
139 * インポートされたキャラクターデータ.<br>
141 private CharacterData importedCharacterData;
145 * 現在表示中もしくは選択中のプロファイル.<br>
148 private final CharacterData targetCd;
151 private CardLayout mainPanelLayout;
153 private ImportWizardCardPanel activePanel;
155 private AbstractAction actNext;
157 private AbstractAction actPrev;
159 private AbstractAction actFinish;
162 protected ImportFileSelectPanel importFileSelectPanel;
164 protected ImportTypeSelectPanel importTypeSelectPanel;
166 protected ImportPartsSelectPanel importPartsSelectPanel;
168 protected ImportPresetSelectPanel importPresetSelectPanel;
170 protected ImportModel importModel = new ImportModel();
173 * プロファイルにパーツデータ・プリセットデータをインポートします.<br>
178 * 更新対象となる現在のプロファイル(新規インポートの場合はnull)
180 public ImportWizardDialog(JFrame parent, CharacterData current) {
182 this.targetCd = current;
183 if (targetCd != null && !targetCd.getDocBase().getScheme().equals("file")) {
184 throw new IllegalArgumentException("ファイルベース以外のキャラクターデータにインポートできません");
186 if (targetCd != null && !targetCd.isValid()) {
187 throw new IllegalArgumentException("妥当でないキャラクターデータにはインポートできません");
193 * プロファイルにパーツデータ・プリセットデータをインポートします.<br>
198 * 選択していてるプロファイル、新規インポートの場合はnull
200 public ImportWizardDialog(JDialog parent, CharacterData current) {
202 this.targetCd = current;
203 if (targetCd != null && !targetCd.getDocBase().getScheme().equals("file")) {
204 throw new IllegalArgumentException("ファイルベース以外のキャラクターデータにインポートできません");
206 if (targetCd != null && !targetCd.isValid()) {
207 throw new IllegalArgumentException("妥当でないキャラクターデータにはインポートできません");
213 * インポート先のキャラクターデータを返す。新規の場合はnull
214 * @return インポート先、新規の場合はnull
216 public CharacterData getTargetCharacterData() {
217 if (targetCd != null && !targetCd.getDocBase().getScheme().equals("file")) {
218 throw new IllegalStateException("ファイルベース以外のキャラクターデータにインポートできません: " + targetCd);
225 * アーカイブファィルまたはディレクトリの初期選択、なければnullまたは空
227 public void initSelectFile(File initFile) {
228 importFileSelectPanel.setSelectFile(initFile);
231 public void initSelectURL(String url) {
232 importFileSelectPanel.initSelectURL(url);
236 * ウィザードダイアログのコンポーネントを初期化します.<br>
237 * currentがnullの場合は新規インポート、そうでない場合は更新インポートとります。
239 private void initComponent() {
241 setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
242 addWindowListener(new WindowAdapter() {
244 public void windowClosing(WindowEvent e) {
249 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
250 .getLocalizedProperties(STRINGS_RESOURCE);
253 if (targetCd == null) {
254 setTitle(strings.getProperty("title.new"));
256 setTitle(strings.getProperty("title.update"));
261 ScaleSupport scaleSupport = ScaleSupport.getInstance(this);
263 Container contentPane = getContentPane();
264 contentPane.setLayout(new BorderLayout());
266 final JPanel mainPanel = new JPanel();
267 mainPanel.setBorder(BorderFactory.createEtchedBorder());
268 int gap = (int)(5 * scaleSupport.getManualScaleX());
269 this.mainPanelLayout = new CardLayout(gap, gap);
270 mainPanel.setLayout(mainPanelLayout);
271 contentPane.add(mainPanel, BorderLayout.CENTER);
273 ChangeListener changeListener = new ChangeListener() {
274 public void stateChanged(ChangeEvent e) {
275 updateBtnPanelState();
279 ComponentListener componentListener = new ComponentAdapter() {
280 public void componentShown(ComponentEvent e) {
281 onComponentShown((ImportWizardCardPanel) e.getComponent());
288 this.actNext = new AbstractAction(strings.getProperty("btn.next")) {
289 private static final long serialVersionUID = 1L;
290 public void actionPerformed(ActionEvent e) {
291 setEnableButtons(false);
292 String nextPanelName = doNext();
293 if (nextPanelName != null) {
294 mainPanelLayout.show(mainPanel, nextPanelName);
296 // 移動先ページ名なければ、現在のページでボタン状態を再設定する.
297 // 移動先ページ名がある場合、実際に移動し表示されるまでディセーブルのままとする.
298 updateBtnPanelState();
302 this.actPrev = new AbstractAction(strings.getProperty("btn.prev")) {
303 private static final long serialVersionUID = 1L;
304 public void actionPerformed(ActionEvent e) {
305 setEnableButtons(false);
306 String prevPanelName = doPrevious();
307 if (prevPanelName != null) {
308 mainPanelLayout.show(mainPanel, prevPanelName);
310 updateBtnPanelState();
314 this.actFinish = new AbstractAction(strings.getProperty("btn.finish")) {
315 private static final long serialVersionUID = 1L;
316 public void actionPerformed(ActionEvent e) {
320 AbstractAction actCancel = new AbstractAction(strings.getProperty("btn.cancel")) {
321 private static final long serialVersionUID = 1L;
322 public void actionPerformed(ActionEvent e) {
327 // ImportFileSelectPanel
328 this.importFileSelectPanel = new ImportFileSelectPanel(scaleSupport);
329 this.importFileSelectPanel.addComponentListener(componentListener);
330 this.importFileSelectPanel.addChangeListener(changeListener);
331 mainPanel.add(this.importFileSelectPanel, ImportFileSelectPanel.PANEL_NAME);
333 // ImportTypeSelectPanel
334 this.importTypeSelectPanel = new ImportTypeSelectPanel(scaleSupport);
335 this.importTypeSelectPanel.addComponentListener(componentListener);
336 this.importTypeSelectPanel.addChangeListener(changeListener);
337 mainPanel.add(this.importTypeSelectPanel, ImportTypeSelectPanel.PANEL_NAME);
339 // ImportPartsSelectPanel
340 this.importPartsSelectPanel = new ImportPartsSelectPanel(scaleSupport);
341 this.importPartsSelectPanel.addComponentListener(componentListener);
342 this.importPartsSelectPanel.addChangeListener(changeListener);
343 mainPanel.add(this.importPartsSelectPanel, ImportPartsSelectPanel.PANEL_NAME);
345 // ImportPresetSelectPanel
346 this.importPresetSelectPanel = new ImportPresetSelectPanel(scaleSupport);
347 this.importPresetSelectPanel.addComponentListener(componentListener);
348 this.importPresetSelectPanel.addChangeListener(changeListener);
349 mainPanel.add(this.importPresetSelectPanel, ImportPresetSelectPanel.PANEL_NAME);
354 JPanel btnPanel = new JPanel();
355 int mergin = (int)(3 * scaleSupport.getManualScaleX());
356 btnPanel.setBorder(BorderFactory.createEmptyBorder(mergin, mergin, mergin, mergin * 15)); // 3,3,3,45
357 GridBagLayout btnPanelLayout = new GridBagLayout();
358 btnPanel.setLayout(btnPanelLayout);
360 actPrev.setEnabled(false);
361 actNext.setEnabled(false);
362 actFinish.setEnabled(false);
364 GridBagConstraints gbc = new GridBagConstraints();
370 gbc.anchor = GridBagConstraints.EAST;
371 gbc.fill = GridBagConstraints.BOTH;
374 gbc.insets = new Insets(mergin, mergin, mergin, mergin);
377 btnPanel.add(Box.createHorizontalGlue(), gbc);
379 gbc.gridx = Main.isLinuxOrMacOSX() ? 2 : 1;
382 btnPanel.add(new JButton(this.actPrev), gbc);
384 gbc.gridx = Main.isLinuxOrMacOSX() ? 3 : 2;
386 JButton btnNext = new JButton(this.actNext);
387 btnPanel.add(btnNext, gbc);
389 gbc.gridx = Main.isLinuxOrMacOSX() ? 4 : 3;
391 btnPanel.add(new JButton(this.actFinish), gbc);
393 gbc.gridx = Main.isLinuxOrMacOSX() ? 1 : 4;
395 JButton btnCancel = new JButton(actCancel);
396 btnPanel.add(btnCancel, gbc);
398 contentPane.add(btnPanel, BorderLayout.SOUTH);
402 Toolkit tk = Toolkit.getDefaultToolkit();
403 JRootPane rootPane = getRootPane();
405 rootPane.setDefaultButton(btnNext);
407 InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
408 ActionMap am = rootPane.getActionMap();
409 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closeImportWizDialog");
410 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "closeImportWizDialog");
411 am.put("closeImportWizDialog", actCancel);
415 Dimension dim = new Dimension(500, 500);
416 // HiDpi環境でのスケールを考慮したウィンドウサイズに補正する
417 dim = scaleSupport.manualScaled(dim);
419 setLocationRelativeTo(getParent());
421 mainPanelLayout.first(mainPanel);
422 updateBtnPanelState();
425 protected void onComponentShown(JPanel panel) {
426 ImportWizardCardPanel activePanel = (ImportWizardCardPanel) panel;
427 activePanel.onActive(this, this.activePanel);
428 this.activePanel = activePanel;
429 updateBtnPanelState();
432 protected void updateBtnPanelState() {
433 if (activePanel != null) {
434 actPrev.setEnabled(activePanel.isReadyPrevious());
435 actNext.setEnabled(activePanel.isReadyNext());
436 actFinish.setEnabled(activePanel.isReadyFinish());
439 setEnableButtons(false);
443 public void setEnableButtons(boolean enabled) {
444 actPrev.setEnabled(enabled);
445 actNext.setEnabled(enabled);
446 actFinish.setEnabled(enabled);
449 protected String doNext() {
450 if (activePanel == null) {
451 throw new IllegalStateException();
453 String nextPanelName;
455 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
457 nextPanelName = activePanel.doNext();
459 setCursor(Cursor.getDefaultCursor());
461 return nextPanelName;
464 protected String doPrevious() {
465 if (activePanel == null) {
466 throw new IllegalStateException();
468 return activePanel.doPrevious();
471 protected void onClose() {
472 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
473 .getLocalizedProperties(STRINGS_RESOURCE);
475 if (JOptionPane.showConfirmDialog(this,
476 strings.getProperty("confirm.close"),
477 strings.getProperty("confirm"),
478 JOptionPane.YES_NO_OPTION,
479 JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION) {
484 importFileSelectPanel.closeArchive();
487 this.exitCode = EXIT_CANCELED;
488 this.importedCharacterData = null;
497 protected void onFinish() {
498 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
499 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
502 // 新規プロファイル作成、または更新の実行
503 setEnableButtons(false);
504 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
506 CharacterData importedCharacterData;
508 if (targetCd == null) {
510 importedCharacterData = createNewProfile();
511 exitCode = EXIT_PROFILE_CREATED;
514 importedCharacterData = updateProfile(targetCd.duplicateBasicInfo());
515 exitCode = EXIT_PROFILE_UPDATED;
518 setCursor(Cursor.getDefaultCursor());
522 importFileSelectPanel.closeArchive();
525 JOptionPane.showMessageDialog(this, strings.getProperty("complete"));
528 this.exitCode = exitCode;
529 this.importedCharacterData = importedCharacterData;
532 } catch (Exception ex) {
533 ErrorMessageHelper.showErrorDialog(this, ex);
534 // ディセーブルにしていたボタンをパネルの状態に戻す.
535 updateBtnPanelState();
540 * ウィザードが閉じられた場合の終了コード. {@link #EXIT_PROFILE_UPDATED}であればプロファイルが更新されており,<br>
541 * {@link #EXIT_PROFILE_CREATED}であればプロファイルが作成されている.<br>
542 * {@link #EXIT_CANCELED}であればキャンセルされている.<br>
546 public int getExitCode() {
551 * 新規または更新されたプロファイル、キャンセルされた場合はnull
555 public CharacterData getImportedCharacterData() {
556 return importedCharacterData;
560 * アーカイブからの新規プロファイルの作成
562 * @return 作成された新規プロファイル
563 * @throws IOException
566 protected CharacterData createNewProfile() throws IOException {
567 CharacterData cd = importModel.getCharacterData();
568 if (cd == null || !cd.isValid()) {
569 throw new IllegalStateException("imported caharcer data is invalid." + cd);
572 CharacterDataPersistent persist = CharacterDataPersistent.getInstance();
574 CharacterData characterData = cd.duplicateBasicInfo(); // インポートしたキャラクターデータ
575 Map<CustomLayerOrderKey, List<CustomLayerOrder>> customLayerPatterns = importModel.getCustomLayerPatternMap();
577 // キャラクターセット名と作者名を設定する
578 characterData.setName(importTypeSelectPanel.getCharacterName());
579 characterData.setAuthor(importTypeSelectPanel.getAuthor());
582 characterData.clearPartsSets(false);
583 if (importTypeSelectPanel.isImportPreset()) {
584 for (PartsSet partsSet : importPresetSelectPanel.getSelectedPartsSets()) {
585 PartsSet ps = partsSet.clone();
586 ps.setPresetParts(true);
587 characterData.addPartsSet(ps);
589 characterData.setDefaultPartsSetId(importPresetSelectPanel.getPrefferedDefaultPartsSetId());
593 // docBaseが設定されて返される.
594 persist.createProfile(characterData, customLayerPatterns);
597 if (importTypeSelectPanel.isImportPartsImages()) {
599 Collection<PartsImageContent> partsImageContents
600 = importPartsSelectPanel.getSelectedPartsImageContents();
601 importModel.copyPartsImageContents(partsImageContents, characterData);
604 PartsManageData partsManageData = importModel.getPartsManageData();
605 importModel.updatePartsManageData(partsImageContents, partsManageData, null, characterData);
609 if (importTypeSelectPanel.isImportSampleImage()) {
610 BufferedImage samplePicture = importModel.getSamplePicture();
611 if (samplePicture != null) {
612 persist.saveSamplePicture(characterData, samplePicture);
616 return characterData;
622 * @return 更新されたプロファイル
623 * @throws IOException
626 protected CharacterData updateProfile(CharacterData characterData) throws IOException {
627 CharacterDataPersistent persist = CharacterDataPersistent.getInstance();
629 boolean imported = false;
630 boolean modCharacterDef = false;
631 boolean modFavories = false;
634 if (importTypeSelectPanel.isImportPartsImages()) {
636 Collection<PartsImageContent> partsImageContents
637 = importPartsSelectPanel.getSelectedPartsImageContents();
638 importModel.copyPartsImageContents(partsImageContents, characterData);
641 PartsManageData partsManageData = importModel.getPartsManageData();
642 importModel.updatePartsManageData(partsImageContents, partsManageData, characterData, characterData);
648 if (importTypeSelectPanel.isImportSampleImage()) {
649 BufferedImage samplePicture = importModel.getSamplePicture();
650 if (samplePicture != null) {
651 persist.saveSamplePicture(characterData, samplePicture);
657 if (importTypeSelectPanel.isImportPreset()) {
658 for (PartsSet partsSet : importPresetSelectPanel.getSelectedPartsSets()) {
659 PartsSet ps = partsSet.clone();
660 ps.setPresetParts(false);
661 characterData.addPartsSet(ps);
664 modCharacterDef = true;
669 if (importTypeSelectPanel.isAddDescription() && imported) {
670 URI archivedFile = importModel.getImportSource();
671 String note = importTypeSelectPanel.getAdditionalDescription();
672 if (note != null && note.length() > 0) {
673 String description = characterData.getDescription();
674 if (description == null) {
677 String lf = System.getProperty("line.separator");
678 Timestamp tm = new Timestamp(System.currentTimeMillis());
679 description += lf + "--- import: " + tm + " : " + archivedFile + " ---" + lf;
680 description += note + lf;
681 characterData.setDescription(description);
682 modCharacterDef = true;
687 if (modCharacterDef) {
688 persist.updateProfile(characterData); // キャラクター定義の構造に変化なし
689 targetCd.setDescription(characterData.getDescription()); // 現在保持しているCdの説明文は更新しておく(念のため)
693 persist.saveFavorites(characterData);
696 return characterData;
707 abstract class ImportWizardCardPanel extends JPanel {
709 private static final long serialVersionUID = 1L;
711 private LinkedList<ChangeListener> listeners = new LinkedList<ChangeListener>();
713 public void addChangeListener(ChangeListener l) {
719 public void removeChangeListener(ChangeListener l) {
725 public void fireChangeEvent() {
726 ChangeEvent e = new ChangeEvent(this);
727 for (ChangeListener l : listeners) {
732 public void onActive(ImportWizardDialog parent, ImportWizardCardPanel previousPanel) {
736 public boolean isReadyPrevious() {
740 public boolean isReadyNext() {
744 public boolean isReadyFinish() {
748 public String doNext() {
749 throw new UnsupportedOperationException();
752 public String doPrevious() {
753 throw new UnsupportedOperationException();
762 class ImportFileSelectPanel extends ImportWizardCardPanel {
764 private static final long serialVersionUID = 1L;
766 public static final String PANEL_NAME = "fileSelectPanel";
771 private static ArchiveFileDialog archiveFileDialog = new ArchiveFileDialog();
773 private ImportWizardDialog parent;
778 private JRadioButton radioArchiveFile;
783 private JTextField txtArchiveFile;
788 private Action actChooseFile;
794 private JRadioButton radioDirectory;
799 private JTextField txtDirectory;
804 private Action actChooseDirectory;
810 private JRadioButton radioURL;
815 private JTextField txtURL;
818 /* 以下、対象ファイルの読み取り結果 */
821 public ImportFileSelectPanel(ScaleSupport scaleSupport) {
822 setLayout(new BorderLayout());
824 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
825 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
827 DocumentListener documentListener = new DocumentListener() {
828 public void removeUpdate(DocumentEvent e) {
831 public void insertUpdate(DocumentEvent e) {
834 public void changedUpdate(DocumentEvent e) {
837 protected void fireEvent() {
842 txtArchiveFile = new JTextField();
843 txtDirectory = new JTextField();
844 txtURL = new JTextField();
846 txtArchiveFile.getDocument().addDocumentListener(documentListener);
847 txtDirectory.getDocument().addDocumentListener(documentListener);
848 txtURL.getDocument().addDocumentListener(documentListener);
850 actChooseFile = new AbstractAction(strings.getProperty("browse")) {
851 private static final long serialVersionUID = 1L;
852 public void actionPerformed(ActionEvent e) {
857 actChooseDirectory = new AbstractAction(strings.getProperty("browse")) {
858 private static final long serialVersionUID = 1L;
859 public void actionPerformed(ActionEvent e) {
865 JPanel fileChoosePanel = new JPanel();
866 GridBagLayout fileChoosePanelLayout = new GridBagLayout();
867 fileChoosePanel.setLayout(fileChoosePanelLayout);
869 radioArchiveFile = new JRadioButton(strings.getProperty("importingArchiveFile"));
870 radioDirectory = new JRadioButton(strings.getProperty("importingDirectory"));
871 radioURL = new JRadioButton(strings.getProperty("importingURL"));
873 ChangeListener radioChangeListener = new ChangeListener() {
874 public void stateChanged(ChangeEvent e) {
879 radioArchiveFile.addChangeListener(radioChangeListener);
880 radioDirectory.addChangeListener(radioChangeListener);
881 radioURL.addChangeListener(radioChangeListener);
883 ButtonGroup btnGroup = new ButtonGroup();
884 btnGroup.add(radioArchiveFile);
885 btnGroup.add(radioDirectory);
886 btnGroup.add(radioURL);
888 // アーカイブからのインポートをデフォルトとする
889 radioArchiveFile.setSelected(true);
891 GridBagConstraints gbc = new GridBagConstraints();
895 int gap = (int)(3 * scaleSupport.getManualScaleX());
896 gbc.insets = new Insets(gap, gap, gap, gap);
897 gbc.anchor = GridBagConstraints.WEST;
898 gbc.fill = GridBagConstraints.BOTH;
907 fileChoosePanel.add(radioArchiveFile, gbc);
914 fileChoosePanel.add(Box.createHorizontalGlue(), gbc);
920 fileChoosePanel.add(txtArchiveFile, gbc);
926 fileChoosePanel.add(new JButton(actChooseFile), gbc);
934 fileChoosePanel.add(radioDirectory, gbc);
941 fileChoosePanel.add(Box.createHorizontalGlue(), gbc);
947 fileChoosePanel.add(txtDirectory, gbc);
953 fileChoosePanel.add(new JButton(actChooseDirectory), gbc);
962 fileChoosePanel.add(radioURL, gbc);
969 fileChoosePanel.add(Box.createHorizontalGlue(), gbc);
975 fileChoosePanel.add(txtURL, gbc);
984 fileChoosePanel.add(Box.createGlue(), gbc);
986 add(fileChoosePanel, BorderLayout.CENTER);
989 new DropTarget(this, new FileDropTarget() {
991 protected void onDropFiles(List<File> dropFiles) {
992 if (dropFiles == null || dropFiles.isEmpty()) {
995 File dropFile = dropFiles.get(0);
996 setSelectFile(dropFile);
1000 protected void onException(Exception ex) {
1001 ErrorMessageHelper.showErrorDialog(ImportFileSelectPanel.this, ex);
1009 * アーカイブファイルまたはディレクトリを選択状態とする.<br>
1013 * アーカイブファイルまたはディレクトリ、もしくはnull
1015 public void setSelectFile(File dropFile) {
1016 if (dropFile == null) {
1018 txtDirectory.setText("");
1019 txtArchiveFile.setText("");
1021 radioDirectory.setSelected(false);
1022 radioArchiveFile.setSelected(false);
1023 radioURL.setSelected(false);
1025 } else if (dropFile.isDirectory()) {
1027 txtDirectory.setText(dropFile.getPath());
1028 radioDirectory.setSelected(true);
1030 } else if (dropFile.isFile()) {
1032 txtArchiveFile.setText(dropFile.getPath());
1033 radioArchiveFile.setSelected(true);
1041 public void initSelectURL(String url) {
1042 if (url != null && (url.startsWith("http://") || url.startsWith("https://"))) {
1044 txtURL.setText(url);
1045 radioURL.setSelected(true);
1049 txtDirectory.setText("");
1050 txtArchiveFile.setText("");
1052 radioDirectory.setSelected(false);
1053 radioArchiveFile.setSelected(false);
1054 radioURL.setSelected(false);
1058 protected void updateUIState() {
1059 boolean enableArchiveFile = radioArchiveFile.isSelected();
1060 boolean enableDirectory = radioDirectory.isSelected();
1061 boolean enableURL = radioURL.isSelected();
1063 txtArchiveFile.setEnabled(enableArchiveFile);
1064 actChooseFile.setEnabled(enableArchiveFile);
1066 txtDirectory.setEnabled(enableDirectory);
1067 actChooseDirectory.setEnabled(enableDirectory);
1069 txtURL.setEnabled(enableURL);
1072 protected void onChooseFile() {
1073 File initFile = null;
1074 if (txtArchiveFile.getText().trim().length() > 0) {
1075 initFile = new File(txtArchiveFile.getText());
1077 File file = archiveFileDialog.showOpenDialog(this, initFile);
1079 txtArchiveFile.setText(file.getPath());
1084 protected void onChooseDirectory() {
1085 String directoryTxt = txtDirectory.getText();
1086 JFileChooser dirChooser = new JFileChooser(directoryTxt);
1087 dirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
1089 if (dirChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) {
1092 File dir = dirChooser.getSelectedFile();
1094 txtDirectory.setText(dir.getPath());
1100 public boolean isReadyNext() {
1101 if (radioArchiveFile.isSelected()) {
1102 String fileTxt = txtArchiveFile.getText();
1103 if (fileTxt != null && fileTxt.trim().length() > 0) {
1106 } else if (radioDirectory.isSelected()) {
1107 String directoryTxt = txtDirectory.getText();
1108 if (directoryTxt != null && directoryTxt.trim().length() > 0) {
1111 } else if (radioURL.isSelected()) {
1112 String url = txtURL.getText();
1113 if (url != null && (url.startsWith("http://") || url.startsWith("https://"))) {
1121 public void onActive(ImportWizardDialog parent, ImportWizardCardPanel previousPanel) {
1122 this.parent = parent;
1124 // 開いているアーカイブがあれば閉じる
1129 * 開いているアーカイブがあればクローズする.
1131 public void closeArchive() {
1133 parent.importModel.closeImportSource();
1135 } catch (IOException ex) {
1136 ErrorMessageHelper.showErrorDialog(this, ex);
1137 // エラーが発生しても、とりあえず無視する.
1142 public String doNext() {
1143 if (!isReadyNext()) {
1147 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
1148 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
1151 if (radioArchiveFile.isSelected()) {
1153 File file = new File(txtArchiveFile.getText());
1154 if (!file.exists() || !file.isFile()) {
1155 JOptionPane.showMessageDialog(this, strings
1156 .getProperty("fileNotFound"), "ERROR",
1157 JOptionPane.ERROR_MESSAGE);
1160 importArchive = file.toURI();
1162 } else if (radioDirectory.isSelected()) {
1164 File file = new File(txtDirectory.getText());
1165 if ( !file.exists() || !file.isDirectory()) {
1166 JOptionPane.showMessageDialog(this, strings
1167 .getProperty("directoryNotFound"), "ERROR",
1168 JOptionPane.ERROR_MESSAGE);
1171 importArchive = file.toURI();
1173 } else if (radioURL.isSelected()) {
1175 File tmpFile = loadTemporaryFromURL(txtURL.getText());
1176 if (tmpFile == null) {
1177 // エラーメッセージは表示済みのため、単にnullでnextを拒否する
1180 importArchive = tmpFile.toURI();
1188 parent.importModel.openImportSource(importArchive, parent.getTargetCharacterData());
1190 // ワーカースレッドでアーカイブの読み込みを行う.
1191 Worker<Void> worker = new Worker<Void>() {
1192 public Void doWork(ProgressHandle progressHandle) throws IOException {
1193 parent.importModel.loadContents(progressHandle);
1198 WorkerWithProgessDialog<Void> dlg = new WorkerWithProgessDialog<Void>(parent, worker);
1202 return ImportTypeSelectPanel.PANEL_NAME;
1204 } catch (WorkerException ex) {
1205 ErrorMessageHelper.showErrorDialog(this, ex.getCause());
1207 } catch (Exception ex) {
1208 ErrorMessageHelper.showErrorDialog(this, ex);
1215 * 指定されたURLからテンポラリにダウンロードして、そのファイルを返す。
1216 * URLが適切でない場合、もしくはエラーが発生した場合はnullを返す。
1218 * @return ダウンロードしたファイル
1220 private File loadTemporaryFromURL(final String url) {
1221 final Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
1222 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
1223 final AppConfig appConfig = AppConfig.getInstance();
1224 final DownloadUtils downloader = new DownloadUtils();
1225 downloader.setImpersonateUserAgent(appConfig.getImpersonateUserAgent());
1226 downloader.setDeleteDownloadFileOnExit(appConfig.isDeleteDownloadFileOnExit());
1229 // ワーカースレッドでアーカイブの読み込みを行う.
1230 Worker<File> worker = new Worker<File>() {
1231 public File doWork(ProgressHandle progressHandle) throws IOException {
1232 progressHandle.setIndeterminate(true);
1233 progressHandle.setCaption(strings.getProperty("downloading.checkhead"));
1235 HeadResponse headResponse = downloader.getHead(url);
1237 String contentType = headResponse.getContentType();
1238 String ext = headResponse.getDotExtension();
1239 CharacterDataFileReaderWriterFactory archiveRdWrFactory =
1240 CharacterDataFileReaderWriterFactory.getInstance();
1241 if (contentType == null || !contentType.startsWith("application/") ||
1242 !archiveRdWrFactory.isSupportedFile(ext)) {
1243 // コンテンツタイプが不明、もしくはバイナリではない
1244 // あるいは、ファイル名がzip, jar, cmjのいずれでもない場合
1248 progressHandle.setCaption(strings.getProperty("downloading.waitForDownload"));
1249 return downloader.downloadTemporary(headResponse);
1253 WorkerWithProgessDialog<File> dlg = new WorkerWithProgessDialog<File>(parent, worker);
1255 File tempFile = dlg.startAndWait();
1256 if (tempFile != null) {
1259 JOptionPane.showMessageDialog(this, strings.getProperty("downloading.invalidFileType"),
1260 "ERROR", JOptionPane.ERROR_MESSAGE);
1263 } catch (WorkerException ex) {
1264 Throwable iex = ex.getCause();
1265 throw (iex == null) ? ex : (Exception) iex;
1268 } catch (FileNotFoundException ex) {
1269 JOptionPane.showMessageDialog(this, strings.getProperty("downloading.notFound"),
1270 "ERROR", JOptionPane.ERROR_MESSAGE);
1272 } catch (Exception ex) {
1273 ErrorMessageHelper.showErrorDialog(this, ex);
1281 private String downloadURL;
1283 private String author;
1285 public String getAuthor() {
1289 public String getDownloadURL() {
1293 public void setAuthor(String author) {
1294 this.author = author;
1297 public void setDownloadURL(String downloadURL) {
1298 this.downloadURL = downloadURL;
1303 class URLTableModel extends AbstractTableModelWithComboBoxModel<URLTableRow> {
1305 private static final long serialVersionUID = 7075478118793390224L;
1307 private static final String[] COLUMN_NAMES;
1309 private static final int[] COLUMN_WIDTHS;
1312 COLUMN_NAMES = new String[] {
1316 COLUMN_WIDTHS = new int[] {
1323 public String getColumnName(int column) {
1324 return COLUMN_NAMES[column];
1327 public int getColumnCount() {
1328 return COLUMN_NAMES.length;
1331 public Object getValueAt(int rowIndex, int columnIndex) {
1332 URLTableRow row = getRow(rowIndex);
1333 switch (columnIndex) {
1335 return row.getAuthor();
1337 return row.getDownloadURL();
1343 public Class<?> getColumnClass(int columnIndex) {
1344 return String.class;
1348 public void adjustColumnModel(TableColumnModel columnModel, double scale) {
1349 for (int idx = 0; idx < COLUMN_WIDTHS.length; idx++) {
1350 columnModel.getColumn(idx).setPreferredWidth((int)(COLUMN_WIDTHS[idx] * scale));
1354 public void initModel(CharacterData characterData) {
1356 HashMap<String, String> downloadUrlsMap = new HashMap<String, String>();
1357 if (characterData != null) {
1358 for (PartsCategory category : characterData.getPartsCategories()) {
1359 for (Map.Entry<PartsIdentifier, PartsSpec> entry : characterData
1360 .getPartsSpecMap(category).entrySet()) {
1361 PartsSpec partsSpec = entry.getValue();
1362 String author = partsSpec.getAuthor();
1363 String downloadURL = partsSpec.getDownloadURL();
1364 if (downloadURL != null && downloadURL.trim().length() > 0) {
1365 if (author == null || author.trim().length() == 0) {
1368 downloadUrlsMap.put(downloadURL, author);
1374 for (Map.Entry<String, String> entry : downloadUrlsMap.entrySet()) {
1375 String downloadURL = entry.getKey();
1376 String author = entry.getValue();
1377 URLTableRow row = new URLTableRow();
1378 row.setDownloadURL(downloadURL);
1379 row.setAuthor(author);
1383 Collections.sort(elements, new Comparator<URLTableRow>() {
1384 public int compare(URLTableRow o1, URLTableRow o2) {
1385 int ret = o1.getAuthor().compareTo(o2.getAuthor());
1387 ret = o1.getDownloadURL().compareTo(o2.getDownloadURL());
1393 fireTableDataChanged();
1403 class ImportTypeSelectPanel extends ImportWizardCardPanel {
1405 private static final long serialVersionUID = 1L;
1407 public static final String PANEL_NAME = "importTypeSelectPanel";
1409 private ImportWizardDialog parent;
1411 private SamplePicturePanel samplePicturePanel;
1413 private JTextField txtCharacterId;
1415 private JTextField txtCharacterRev;
1417 private JTextField txtCharacterName;
1419 private JTextField txtAuthor;
1421 private JTextArea txtDescription;
1423 private JCheckBox chkPartsImages;
1425 private JCheckBox chkPresets;
1427 private JCheckBox chkSampleImage;
1429 private JCheckBox chkAddDescription;
1431 private String additionalDescription;
1436 public ImportTypeSelectPanel(ScaleSupport scaleSupport) {
1437 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
1438 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
1440 GridBagLayout basicPanelLayout = new GridBagLayout();
1441 GridBagConstraints gbc = new GridBagConstraints();
1442 setLayout(basicPanelLayout);
1444 JPanel contentsSpecPanel = new JPanel();
1445 int mergin = (int)(5 * scaleSupport.getManualScaleX());
1446 contentsSpecPanel.setBorder(BorderFactory.createCompoundBorder(
1447 BorderFactory.createEmptyBorder(mergin, mergin, mergin, mergin),
1448 BorderFactory.createTitledBorder(strings.getProperty("basic.contentsSpec"))));
1449 BoxLayout contentsSpecPanelLayout = new BoxLayout(contentsSpecPanel, BoxLayout.PAGE_AXIS);
1450 contentsSpecPanel.setLayout(contentsSpecPanelLayout);
1452 chkPartsImages = new JCheckBox(strings.getProperty("basic.chk.partsImages"));
1453 chkPresets = new JCheckBox(strings.getProperty("basic.chk.presets"));
1454 chkSampleImage = new JCheckBox(strings.getProperty("basic.chk.samplePicture"));
1456 contentsSpecPanel.add(chkPartsImages);
1457 contentsSpecPanel.add(chkPresets);
1458 contentsSpecPanel.add(chkSampleImage);
1462 JPanel archiveInfoPanel = new JPanel();
1463 archiveInfoPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory
1464 .createEmptyBorder(mergin, mergin, mergin, mergin),
1465 BorderFactory.createTitledBorder(strings.getProperty("basic.archiveInfo"))));
1466 Dimension archiveInfoPanelMinSize = scaleSupport.manualScaled(new Dimension(300, 200));
1467 archiveInfoPanel.setMinimumSize(archiveInfoPanelMinSize);
1468 archiveInfoPanel.setPreferredSize(archiveInfoPanelMinSize);
1469 GridBagLayout commentPanelLayout = new GridBagLayout();
1470 archiveInfoPanel.setLayout(commentPanelLayout);
1478 int gap = (int)(3 * scaleSupport.getManualScaleX());
1479 gbc.insets = new Insets(gap, gap, gap, gap);
1480 gbc.anchor = GridBagConstraints.WEST;
1481 gbc.fill = GridBagConstraints.BOTH;
1489 archiveInfoPanel.add(new JLabel(strings.getProperty("basic.profileId"), JLabel.RIGHT), gbc);
1497 txtCharacterId = new JTextField();
1498 txtCharacterId.setEditable(false); // 読み取り専用
1499 txtCharacterId.setEnabled(false);
1500 archiveInfoPanel.add(txtCharacterId, gbc);
1508 archiveInfoPanel.add(new JLabel(strings.getProperty("basic.profileRev"), JLabel.RIGHT), gbc);
1516 txtCharacterRev = new JTextField();
1517 txtCharacterRev.setEditable(false); // 読み取り専用
1518 txtCharacterRev.setEnabled(false);
1519 archiveInfoPanel.add(txtCharacterRev, gbc);
1527 archiveInfoPanel.add(new JLabel(strings.getProperty("basic.profileName"), JLabel.RIGHT), gbc);
1535 txtCharacterName = new JTextField();
1536 archiveInfoPanel.add(txtCharacterName, gbc);
1544 archiveInfoPanel.add(
1545 new JLabel(strings.getProperty("author"), JLabel.RIGHT), gbc);
1551 txtAuthor = new JTextField();
1552 archiveInfoPanel.add(txtAuthor, gbc);
1559 archiveInfoPanel.add(new JLabel(strings.getProperty("description"),
1560 JLabel.RIGHT), gbc);
1568 txtDescription = new JTextArea(); // 説明は更新可能にしておく。
1569 archiveInfoPanel.add(new JScrollPane(txtDescription), gbc);
1579 chkAddDescription = new JCheckBox(strings.getProperty("appendDescription"));
1580 archiveInfoPanel.add(chkAddDescription, gbc);
1584 samplePicturePanel = new SamplePicturePanel();
1585 JScrollPane samplePicturePanelSP = new JScrollPane(samplePicturePanel);
1586 samplePicturePanelSP.setBorder(null);
1587 JPanel samplePictureTitledPanel = new JPanel(new BorderLayout());
1588 samplePictureTitledPanel.add(samplePicturePanelSP, BorderLayout.CENTER);
1589 samplePictureTitledPanel.setBorder(BorderFactory.createCompoundBorder(
1590 BorderFactory.createEmptyBorder(mergin, mergin, mergin, mergin),
1591 BorderFactory.createTitledBorder(strings.getProperty("basic.sampleImage"))));
1601 gbc.anchor = GridBagConstraints.WEST;
1602 gbc.fill = GridBagConstraints.BOTH;
1603 add(contentsSpecPanel, gbc);
1611 gbc.anchor = GridBagConstraints.WEST;
1612 gbc.fill = GridBagConstraints.BOTH;
1613 add(archiveInfoPanel, gbc);
1621 gbc.anchor = GridBagConstraints.WEST;
1622 gbc.fill = GridBagConstraints.BOTH;
1623 add(samplePictureTitledPanel, gbc);
1627 ActionListener modListener = new ActionListener() {
1628 public void actionPerformed(ActionEvent e) {
1633 chkPartsImages.addActionListener(modListener);
1634 chkPresets.addActionListener(modListener);
1635 chkSampleImage.addActionListener(modListener);
1636 chkAddDescription.addActionListener(modListener);
1640 public void onActive(ImportWizardDialog parent, ImportWizardCardPanel previousPanel) {
1641 this.parent = parent;
1643 if (previousPanel == parent.importPartsSelectPanel) {
1647 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
1648 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
1651 CharacterData current = parent.getTargetCharacterData();
1654 CharacterData cd = parent.importModel.getCharacterData();
1657 // 開いているか選択しているプロファイルが有効であれば更新可能
1658 final boolean updatable = (current != null && current.isValid());
1660 // 新規の場合でインポートもとが有効なキャラクターセットであれば作成可能
1661 final boolean creatable = (current == null && cd != null && cd.isValid());
1663 // 新規作成の場合はキャラクター定義名と作者名を更新可能とする
1664 txtCharacterName.setEnabled(current == null);
1665 txtCharacterName.setEditable(current == null);
1666 txtAuthor.setEditable(current == null);
1667 txtAuthor.setEnabled(current == null);
1670 boolean matchID = false;
1671 boolean matchREV = false;
1673 if (cd != null && cd.isValid()) {
1674 txtCharacterId.setText(cd.getId());
1675 txtCharacterRev.setText(cd.getRev());
1676 txtCharacterName.setText(cd.getName());
1678 if (current != null) {
1679 // 既存のプロファイルを選択していてインポート結果のキャラクター定義がある場合はID, REVを比較する.
1680 matchID = current.getId() == null ? cd.getId() == null : current.getId().equals(cd.getId());
1681 matchREV = current.getRev() == null ? cd.getRev() == null : current.getRev().equals(cd.getRev());
1683 // 既存のプロファイルが存在しない場合は、ID,REVの比較は成功とみなす
1688 AppConfig appConfig = AppConfig.getInstance();
1689 Color invalidBgColor = appConfig.getInvalidBgColor();
1691 txtCharacterId.setBackground(matchID ? getBackground() : invalidBgColor);
1692 txtCharacterRev.setBackground(matchREV ? getBackground() : invalidBgColor);
1694 txtAuthor.setText(cd.getAuthor());
1695 readme = cd.getDescription();
1698 // ID, REV等は存在しないので空にする
1699 txtCharacterId.setText("");
1700 txtCharacterRev.setText("");
1701 txtCharacterName.setText("");
1702 txtAuthor.setText("");
1705 readme = parent.importModel.getReadme();
1709 boolean existsReadme = (readme != null && readme.trim().length() > 0);
1710 additionalDescription = existsReadme ? readme : "";
1711 txtDescription.setText(additionalDescription);
1712 chkAddDescription.setEnabled((updatable || creatable) && existsReadme);
1713 chkAddDescription.setSelected((updatable || creatable) && existsReadme);
1715 // プリセットまたはお気に入りが存在するか?
1716 boolean hasPresetOrFavorites = (cd == null) ? false : !cd.getPartsSets().isEmpty();
1717 chkPresets.setEnabled(hasPresetOrFavorites);
1718 chkPresets.setSelected(hasPresetOrFavorites);
1721 Collection<PartsImageContent> partsImageContentsMap = parent.importModel.getPartsImageContents();
1724 boolean hasParts = !partsImageContentsMap.isEmpty();
1725 chkPartsImages.setEnabled(hasParts);
1726 chkPartsImages.setSelected(hasParts);
1729 BufferedImage samplePicture = parent.importModel.getSamplePicture();
1730 if (samplePicture != null && (updatable || creatable)) {
1731 // サンプルピクチャが存在し、インポートか新規作成が可能であれば有効にする.
1732 samplePicturePanel.setSamplePicture(samplePicture);
1733 chkSampleImage.setEnabled(true);
1734 chkSampleImage.setSelected(current == null); // 新規作成の場合のみデフォルトでON
1737 samplePicturePanel.setSamplePicture(samplePicture);
1738 chkSampleImage.setEnabled(false);
1739 chkSampleImage.setSelected(false);
1742 // パーツまたはお気に入り・プリセットが存在する場合、
1743 // および、新規の場合はキャラクター定義が存在する場合はコンテンツ有り
1744 boolean hasContents = hasParts || hasPresetOrFavorites
1745 || (current == null && cd != null && cd.isValid());
1748 JOptionPane.showMessageDialog(this, strings.getProperty("noContents"));
1750 } else if (cd == null) {
1751 JOptionPane.showMessageDialog(this, strings.getProperty("notFormalArchive"));
1753 } else if (!matchID) {
1754 String fmt = strings.getProperty("unmatchedProfileId");
1755 String msg = MessageFormat.format(fmt,
1756 cd.getId() == null ? "" : cd.getId());
1757 JOptionPane.showMessageDialog(this, msg);
1759 } else if (!matchREV) {
1760 String fmt = strings.getProperty("unmatchedProfileRev");
1761 String msg = MessageFormat.format(fmt, cd.getRev() == null
1764 JOptionPane.showMessageDialog(this, msg);
1768 public boolean isImportPreset() {
1769 return chkPresets.isSelected();
1772 public boolean isImportPartsImages() {
1773 return chkPartsImages.isSelected();
1776 public boolean isImportSampleImage() {
1777 return chkSampleImage.isSelected();
1780 public boolean isAddDescription() {
1781 return chkAddDescription.isSelected();
1785 * 説明として追加するドキュメント.<Br>
1786 * これはユーザーが編集可能であり、ユーザー編集後の値が取得される.<br>
1788 * @return 説明として追加するドキュメント
1790 public String getAdditionalDescription() {
1791 return txtDescription.getText();
1799 public String getCharacterName() {
1800 return txtCharacterName.getText();
1808 public String getAuthor() {
1809 return txtAuthor.getText();
1813 public boolean isReadyPrevious() {
1818 public String doPrevious() {
1819 return ImportFileSelectPanel.PANEL_NAME;
1823 public boolean isReadyNext() {
1824 if (isImportPartsImages() || isImportPreset()) {
1825 // パーツイメージの選択もしくはパーツセットの選択を指定している場合は次へ進む
1832 public boolean isReadyFinish() {
1833 if (!isImportPartsImages() && !isImportPreset()) {
1834 if ((parent != null && parent.getTargetCharacterData() == null)
1835 || isImportSampleImage()) {
1836 // 新規プロファイル作成か、サンプルイメージの更新のみで
1837 // イメージもパーツセットもいらなければ、ただちに作成可能.
1845 public String doNext() {
1846 return ImportPartsSelectPanel.PANEL_NAME;
1856 class ImportPartsSelectPanel extends ImportWizardCardPanel {
1858 private static final long serialVersionUID = 1L;
1860 public static final String PANEL_NAME = "importPartsSelectPanel";
1862 private ImportWizardDialog parent;
1865 private ImportPartsTableModel partsTableModel;
1867 private JPanel profileSizePanel;
1869 private JTextField txtProfileHeight;
1871 private int profileWidth;
1873 private int profileHeight;
1875 private JTextField txtProfileWidth;
1877 private JTable partsTable;
1879 private Action actSelectAll;
1881 private Action actDeselectAll;
1883 private Action actSort;
1885 private Action actSortByTimestamp;
1888 public ImportPartsSelectPanel(ScaleSupport scaleSupport) {
1889 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
1890 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
1892 setLayout(new BorderLayout());
1894 profileSizePanel = new JPanel();
1895 GridBagLayout profileSizePanelLayout = new GridBagLayout();
1896 profileSizePanel.setLayout(profileSizePanelLayout);
1897 profileSizePanel.setBorder(BorderFactory.createTitledBorder(strings.getProperty("sizeOfProfile")));
1899 GridBagConstraints gbc = new GridBagConstraints();
1905 gbc.anchor = GridBagConstraints.EAST;
1906 gbc.fill = GridBagConstraints.BOTH;
1907 int gap = (int)(3 * scaleSupport.getManualScaleX());
1908 gbc.insets = new Insets(gap, gap, gap, gap);
1913 profileSizePanel.add(new JLabel(strings.getProperty("widthOfProfile"), JLabel.RIGHT), gbc);
1915 txtProfileWidth = new JTextField();
1916 txtProfileWidth.setEditable(false);
1919 profileSizePanel.add(txtProfileWidth, gbc);
1923 profileSizePanel.add(new JLabel(strings.getProperty("heightOfProfile"), JLabel.RIGHT), gbc);
1925 txtProfileHeight = new JTextField();
1926 txtProfileHeight.setEditable(false);
1929 profileSizePanel.add(txtProfileHeight, gbc);
1934 profileSizePanel.add(Box.createHorizontalGlue(), gbc);
1936 add(profileSizePanel, BorderLayout.NORTH);
1938 partsTableModel = new ImportPartsTableModel();
1940 partsTableModel.addTableModelListener(new TableModelListener() {
1941 public void tableChanged(TableModelEvent e) {
1946 AppConfig appConfig = AppConfig.getInstance();
1947 final Color disabledForeground = appConfig.getDisabledCellForgroundColor();
1949 partsTable = new JTable(partsTableModel) {
1950 private static final long serialVersionUID = 1L;
1953 public Component prepareRenderer(TableCellRenderer renderer,
1954 int row, int column) {
1955 Component comp = super.prepareRenderer(renderer, row, column);
1956 if (comp instanceof JCheckBox) {
1957 // BooleanのデフォルトのレンダラーはJCheckBoxを継承したJTable$BooleanRenderer
1958 comp.setEnabled(isCellEditable(row, column) && isEnabled());
1962 ImportPartsTableModel model = (ImportPartsTableModel) getModel();
1963 ImportPartsModel rowModel = model.getRow(row);
1965 Long lastModifiedAtCur = rowModel.getLastModifiedAtCurrentProfile();
1966 if (lastModifiedAtCur != null) {
1968 comp.setFont(getFont().deriveFont(Font.BOLD));
1971 comp.setFont(getFont());
1975 boolean warnings = false;
1976 if (column == ImportPartsTableModel.COLUMN_LASTMODIFIED) {
1977 // 既存のほうが日付が新しければワーニング
1978 if (lastModifiedAtCur != null &&
1979 rowModel.getLastModified() < lastModifiedAtCur.longValue()) {
1982 } else if (column == ImportPartsTableModel.COLUMN_ALPHA) {
1984 if (!rowModel.isAlphaColor()) {
1987 } else if (column == ImportPartsTableModel.COLUMN_SIZE) {
1988 // プロファイルの画像サイズと一致しないか、不揃いな画像であれば警告
1989 if (rowModel.isUnmatchedSize()
1990 || profileWidth != rowModel.getWidth()
1991 || profileHeight != rowModel.getHeight()) {
1997 Color foregroundColor = isCellSelected(row, column) ? getSelectionForeground() : getForeground();
1998 comp.setForeground(isEnabled() ? foregroundColor : disabledForeground);
2002 AppConfig appConfig = AppConfig.getInstance();
2003 Color invalidBgColor = appConfig.getInvalidBgColor();
2004 comp.setBackground(invalidBgColor);
2006 if (isCellSelected(row, column)) {
2007 comp.setBackground(getSelectionBackground());
2009 comp.setBackground(getBackground());
2016 partsTable.setShowGrid(true);
2017 partsTable.setGridColor(appConfig.getGridColor());
2018 partsTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
2019 partsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
2020 partsTable.setRowSelectionAllowed(true);
2023 partsTable.setRowHeight((int)(partsTable.getFont().getSize() * 1.2));
2026 partsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
2027 partsTableModel.adjustColumnModel(partsTable.getColumnModel(), scaleSupport.getManualScaleX());
2029 Action actPartsSetCheck = new AbstractAction(strings.getProperty("parts.popup.check")) {
2030 private static final long serialVersionUID = 1L;
2031 public void actionPerformed(ActionEvent e) {
2032 int[] selRows = partsTable.getSelectedRows();
2033 partsTableModel.setCheck(selRows, true);
2036 Action actPartsUnsetCheck = new AbstractAction(strings.getProperty("parts.popup.uncheck")) {
2037 private static final long serialVersionUID = 1L;
2038 public void actionPerformed(ActionEvent e) {
2039 int[] selRows = partsTable.getSelectedRows();
2040 partsTableModel.setCheck(selRows, false);
2044 final JPopupMenu partsTablePopupMenu = new JPopupMenu();
2045 partsTablePopupMenu.add(actPartsSetCheck);
2046 partsTablePopupMenu.add(actPartsUnsetCheck);
2048 partsTable.setComponentPopupMenu(partsTablePopupMenu);
2050 JScrollPane partsTableSP = new JScrollPane(partsTable);
2051 partsTableSP.setBorder(null);
2052 JPanel partsTableTitledPanel = new JPanel(new BorderLayout());
2053 partsTableTitledPanel.add(partsTableSP, BorderLayout.CENTER);
2054 partsTableTitledPanel.setBorder(BorderFactory.createTitledBorder(strings
2055 .getProperty("parts.title")));
2057 add(partsTableTitledPanel, BorderLayout.CENTER);
2059 actSelectAll = new AbstractAction(strings
2060 .getProperty("parts.btn.selectAll")) {
2061 private static final long serialVersionUID = 1L;
2063 public void actionPerformed(ActionEvent e) {
2067 actDeselectAll = new AbstractAction(strings
2068 .getProperty("parts.btn.deselectAll")) {
2069 private static final long serialVersionUID = 1L;
2071 public void actionPerformed(ActionEvent e) {
2075 actSort = new AbstractAction(strings.getProperty("parts.btn.sort")) {
2076 private static final long serialVersionUID = 1L;
2078 public void actionPerformed(ActionEvent e) {
2082 actSortByTimestamp = new AbstractAction(strings
2083 .getProperty("parts.btn.sortByTimestamp")) {
2084 private static final long serialVersionUID = 1L;
2086 public void actionPerformed(ActionEvent e) {
2087 onSortByTimestamp();
2091 JPanel btnPanel = new JPanel();
2092 GridBagLayout btnPanelLayout = new GridBagLayout();
2093 btnPanel.setLayout(btnPanelLayout);
2099 gbc.anchor = GridBagConstraints.EAST;
2100 gbc.fill = GridBagConstraints.BOTH;
2101 gbc.insets = new Insets(gap, gap, gap, gap);
2104 JButton btnSelectAll = new JButton(actSelectAll);
2105 btnPanel.add(btnSelectAll, gbc);
2109 JButton btnDeselectAll = new JButton(actDeselectAll);
2110 btnPanel.add(btnDeselectAll, gbc);
2114 JButton btnSort = new JButton(actSort);
2115 btnPanel.add(btnSort, gbc);
2119 JButton btnSortByTimestamp = new JButton(actSortByTimestamp);
2120 btnPanel.add(btnSortByTimestamp, gbc);
2125 btnPanel.add(Box.createHorizontalGlue(), gbc);
2127 add(btnPanel, BorderLayout.SOUTH);
2131 public void onActive(ImportWizardDialog parent, ImportWizardCardPanel previousPanel) {
2132 this.parent = parent;
2133 if (previousPanel == parent.importPresetSelectPanel) {
2137 // インポート対象のプロファイルサイズ
2138 CharacterData characterData;
2139 if (parent.getTargetCharacterData() == null) {
2141 characterData = parent.importModel.getCharacterData();
2144 characterData = parent.getTargetCharacterData();
2147 int profileWidth = 0;
2148 int profileHeight = 0;
2149 if (characterData != null) {
2150 Dimension imageSize = characterData.getImageSize();
2151 if (imageSize != null) {
2152 profileWidth = imageSize.width;
2153 profileHeight = imageSize.height;
2156 txtProfileWidth.setText(Integer.toString(profileWidth));
2157 txtProfileHeight.setText(Integer.toString(profileHeight));
2158 profileSizePanel.revalidate();
2159 this.profileHeight = profileHeight;
2160 this.profileWidth = profileWidth;
2162 // パーツのインポート指定があれば編集可能に、そうでなければ表示のみ
2163 // (パーツセットのインポートの確認のため、パーツ一覧は表示できるようにしておく)
2164 boolean enabled = parent.importTypeSelectPanel.isImportPartsImages();
2166 partsTable.setEnabled(enabled);
2167 actDeselectAll.setEnabled(enabled);
2168 actSelectAll.setEnabled(enabled);
2169 actSort.setEnabled(enabled);
2170 actSortByTimestamp.setEnabled(enabled);
2172 CharacterData currentProfile = parent.getTargetCharacterData();
2173 Collection<PartsImageContent> partsImageContents = parent.importModel.getPartsImageContents();
2174 PartsManageData partsManageData = parent.importModel.getPartsManageData();
2175 partsTableModel.initModel(partsImageContents, partsManageData, currentProfile);
2178 Collection<PartsSet> partsSets = null;
2179 if (parent.importTypeSelectPanel.isImportPreset()) {
2180 CharacterData cd = parent.importModel.getCharacterData();
2181 if (cd != null && cd.isValid()) {
2182 partsSets = cd.getPartsSets().values();
2186 final String defaultPartsSetId;
2187 final CharacterData presetImportTarget = parent.getTargetCharacterData();
2188 final boolean selectAllPreset;
2189 if (presetImportTarget == null) { // 新規の場合
2190 CharacterData cd = parent.importModel.getCharacterData();
2192 defaultPartsSetId = cd.getDefaultPartsSetId();
2194 defaultPartsSetId = null;
2196 selectAllPreset = true; // 新規プロファイルの場合はプリセットをインポートする
2198 defaultPartsSetId = null; // 既存の場合はデフォルトのパーツセットであるかは表示する必要ないのでnullにする.
2199 selectAllPreset = (presetImportTarget.getPartsCount() == 0); // パーツが空の場合はプリセットをインポートする
2202 parent.importPresetSelectPanel.initModel(partsSets, defaultPartsSetId, presetImportTarget, selectAllPreset);
2206 public boolean isReadyPrevious() {
2211 public String doPrevious() {
2212 this.partsTableModel.clear();
2213 return ImportTypeSelectPanel.PANEL_NAME;
2217 public boolean isReadyNext() {
2218 if (this.parent != null) {
2219 if (this.parent.importTypeSelectPanel.isImportPreset()) {
2220 // パーツセットのインポート指定があれば次へ
2228 public boolean isReadyFinish() {
2229 if (this.parent != null) {
2230 if (this.parent.importTypeSelectPanel.isImportPartsImages()
2231 && !this.parent.importTypeSelectPanel.isImportPreset()) {
2232 // パーツセットのインポート指定がなければ可
2239 public String doNext() {
2240 return ImportPresetSelectPanel.PANEL_NAME;
2244 protected void onSelectAll() {
2245 partsTableModel.selectAll();
2248 protected void onDeselectAll() {
2249 partsTableModel.deselectAll();
2252 protected void onSort() {
2253 partsTableModel.sort();
2254 if (partsTableModel.getRowCount() > 0) {
2255 Rectangle rct = partsTable.getCellRect(0, 0, true);
2256 partsTable.scrollRectToVisible(rct);
2260 protected void onSortByTimestamp() {
2261 partsTableModel.sortByTimestamp();
2262 if (partsTableModel.getRowCount() > 0) {
2263 Rectangle rct = partsTable.getCellRect(0, 0, true);
2264 partsTable.scrollRectToVisible(rct);
2269 * 選択されたイメージコンテンツのコレクション.<br>
2271 * @return 選択されたイメージコンテンツのコレクション、なければ空
2273 public Collection<PartsImageContent> getSelectedPartsImageContents() {
2274 return partsTableModel.getSelectedPartsImageContents();
2278 * すでにプロファイルに登録済みのパーツ識別子、および、これからインポートする予定の選択されたパーツ識別子のコレクション.<br>
2280 * @return インポートされた、またはインポートするパーツ識別子のコレクション.なければ空.
2282 public Collection<PartsIdentifier> getImportedPartsIdentifiers() {
2283 HashSet<PartsIdentifier> partsIdentifiers = new HashSet<PartsIdentifier>();
2284 partsIdentifiers.addAll(partsTableModel.getCurrentProfilePartsIdentifers());
2285 partsIdentifiers.addAll(partsTableModel.getSelectedPartsIdentifiers());
2286 return partsIdentifiers;
2289 public void selectByPartsIdentifiers(Collection<PartsIdentifier> partsIdentifiers) {
2290 partsTableModel.selectByPartsIdentifiers(partsIdentifiers);
2297 * 同じパーツ名をもつイメージのコレクション.<br>
2298 * パーツの各レイヤーの集合を想定する.<br>
2302 class ImportPartsImageSet extends AbstractCollection<PartsImageContent> {
2307 private String partsName;
2312 private ArrayList<PartsImageContent> contentSet = new ArrayList<PartsImageContent>();
2314 private Long lastModified;
2320 private boolean unmatchedSize;
2322 private boolean alphaColor;
2324 private Collection<PartsCategory> partsCategories;
2326 private boolean checked;
2329 public ImportPartsImageSet(String partsName) {
2330 if (partsName == null || partsName.length() == 0) {
2331 throw new IllegalArgumentException();
2333 this.partsName = partsName;
2336 public String getPartsName() {
2342 return contentSet.size();
2345 public Iterator<PartsImageContent> iterator() {
2346 return contentSet.iterator();
2350 public boolean add(PartsImageContent o) {
2352 throw new IllegalArgumentException();
2354 if (!partsName.equals(o.getPartsName())) {
2355 throw new IllegalArgumentException();
2358 lastModified = null; // リセットする.
2360 return contentSet.add(o);
2363 public int getWidth() {
2368 public int getHeight() {
2373 public boolean isUnmatchedSize() {
2375 return unmatchedSize;
2378 public boolean isAlphaColor() {
2383 public long lastModified() {
2385 return lastModified.longValue();
2388 public Collection<PartsCategory> getPartsCategories() {
2390 return this.partsCategories;
2393 protected void recheck() {
2394 if (lastModified != null) {
2398 long lastModified = 0;
2403 boolean alphaColor = !this.contentSet.isEmpty();
2404 HashSet<PartsCategory> partsCategories = new HashSet<PartsCategory>();
2406 for (PartsImageContent partsImageContent : this.contentSet) {
2407 PNGFileImageHeader header = partsImageContent.getPngFileImageHeader();
2409 maxWidth = Math.max(maxWidth, header.getWidth());
2410 maxHeight = Math.max(maxHeight, header.getHeight());
2411 minWidth = Math.max(minWidth, header.getWidth());
2412 minHeight = Math.max(minHeight, header.getHeight());
2414 if (header.getColorType() != 6 && !header.hasTransparencyInformation()) {
2415 // TrueColor + Alpha (6)か、アルファ情報があるもの以外はアルファなしとする.
2419 for (CategoryLayerPair clPair : partsImageContent.getCategoryLayerPairs()) {
2420 partsCategories.add(clPair.getPartsCategory());
2423 long tm = partsImageContent.lastModified();
2424 lastModified = Math.max(lastModified, tm);
2427 this.lastModified = Long.valueOf(lastModified);
2428 this.width = maxWidth;
2429 this.height = maxHeight;
2430 this.unmatchedSize = (minWidth != maxWidth) || (minHeight != maxHeight);
2431 this.alphaColor = alphaColor;
2432 this.partsCategories = Collections.unmodifiableCollection(partsCategories);
2435 public void setChecked(boolean checked) {
2436 this.checked = checked;
2439 public boolean isChecked() {
2446 class ImportPartsModel {
2448 private PartsIdentifier partsIdentifier;
2450 private PartsAuthorInfo authorInfo;
2452 private PartsManageData.PartsVersionInfo versionInfo;
2454 private PartsSpec partsSpecAtCurrent;
2456 private ImportPartsImageSet imageSet;
2458 private int numOfLink;
2460 private Long lastModifiedAtCurrentProfile;
2466 * @param partsIdentifier
2470 * @param versionInfo
2475 * カテゴリの参照カウント数(複数カテゴリに参照される場合は2以上となる)
2477 public ImportPartsModel(PartsIdentifier partsIdentifier,
2478 PartsAuthorInfo authorInfo,
2479 PartsManageData.PartsVersionInfo versionInfo,
2480 PartsSpec partsSpecAtCurrent,
2481 ImportPartsImageSet imageSet, int numOfLink) {
2482 if (partsIdentifier == null || imageSet == null) {
2483 throw new IllegalArgumentException();
2486 this.partsIdentifier = partsIdentifier;
2487 this.authorInfo = authorInfo;
2488 this.versionInfo = versionInfo;
2489 this.partsSpecAtCurrent = partsSpecAtCurrent;
2490 this.imageSet = imageSet;
2491 this.numOfLink = numOfLink;
2493 if (partsSpecAtCurrent != null) {
2494 lastModifiedAtCurrentProfile = Long.valueOf(partsSpecAtCurrent
2495 .getPartsFiles().lastModified());
2497 lastModifiedAtCurrentProfile = null;
2501 public int getNumOfLink() {
2505 public PartsIdentifier getPartsIdentifier() {
2506 return partsIdentifier;
2509 public ImportPartsImageSet getImageSet() {
2513 public String getPartsName() {
2514 return partsIdentifier.getLocalizedPartsName();
2517 public String getAuthor() {
2518 if (authorInfo != null) {
2519 return authorInfo.getAuthor();
2524 public String getAuthorAtCurrent() {
2525 if (partsSpecAtCurrent != null) {
2526 PartsAuthorInfo partsAuthorInfo = partsSpecAtCurrent.getAuthorInfo();
2527 if (partsAuthorInfo != null) {
2528 return partsAuthorInfo.getAuthor();
2534 public double getVersion() {
2535 if (versionInfo != null) {
2536 return versionInfo.getVersion();
2541 public double getVersionAtCurrent() {
2542 if (partsSpecAtCurrent != null) {
2543 return partsSpecAtCurrent.getVersion();
2548 public PartsCategory getPartsCategory() {
2549 return partsIdentifier.getPartsCategory();
2552 public void setChecked(boolean checked) {
2553 imageSet.setChecked(checked);
2556 public boolean isChecked() {
2557 return imageSet.isChecked();
2560 public int getWidth() {
2561 return imageSet.getWidth();
2564 public int getHeight() {
2565 return imageSet.getHeight();
2568 public boolean isUnmatchedSize() {
2569 return imageSet.isUnmatchedSize();
2572 public boolean isAlphaColor() {
2573 return imageSet.isAlphaColor();
2576 public long getLastModified() {
2577 return imageSet.lastModified();
2580 public Long getLastModifiedAtCurrentProfile() {
2581 return lastModifiedAtCurrentProfile;
2586 class ImportPartsTableModel extends AbstractTableModelWithComboBoxModel<ImportPartsModel> {
2588 private static final long serialVersionUID = 1L;
2590 private static final String[] COLUMN_NAMES;
2592 private static final int[] COLUMN_WIDTHS;
2594 public static final int COLUMN_LASTMODIFIED = 5;
2596 public static final int COLUMN_ALPHA = 4;
2598 public static final int COLUMN_SIZE = 3;
2600 private Set<PartsIdentifier> currentProfilePartsIdentifiers;
2603 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
2604 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
2606 COLUMN_NAMES = new String[] {
2607 strings.getProperty("parts.column.check"),
2608 strings.getProperty("parts.column.partsname"),
2609 strings.getProperty("parts.column.category"),
2610 strings.getProperty("parts.column.imagesize"),
2611 strings.getProperty("parts.column.alpha"),
2612 strings.getProperty("parts.column.lastmodified"),
2613 strings.getProperty("parts.column.org-lastmodified"),
2614 strings.getProperty("parts.column.author"),
2615 strings.getProperty("parts.column.org-author"),
2616 strings.getProperty("parts.column.version"),
2617 strings.getProperty("parts.column.org-version"),
2619 COLUMN_WIDTHS = new int[] {
2620 Integer.parseInt(strings.getProperty("parts.column.check.size")),
2621 Integer.parseInt(strings.getProperty("parts.column.partsname.size")),
2622 Integer.parseInt(strings.getProperty("parts.column.category.size")),
2623 Integer.parseInt(strings.getProperty("parts.column.imagesize.size")),
2624 Integer.parseInt(strings.getProperty("parts.column.alpha.size")),
2625 Integer.parseInt(strings.getProperty("parts.column.lastmodified.size")),
2626 Integer.parseInt(strings.getProperty("parts.column.org-lastmodified.size")),
2627 Integer.parseInt(strings.getProperty("parts.column.author.size")),
2628 Integer.parseInt(strings.getProperty("parts.column.org-author.size")),
2629 Integer.parseInt(strings.getProperty("parts.column.version.size")),
2630 Integer.parseInt(strings.getProperty("parts.column.org-version.size")),
2638 * @param partsImageContents
2639 * インポートもとアーカイブに含まれる、全パーツイメージコンテンツ
2640 * @param currentProfile
2641 * インポート先のプロファイル、現在プロファイルが既に持っているパーツを取得するためのもの。
2643 public void initModel(Collection<PartsImageContent> partsImageContents, PartsManageData partsManageData, CharacterData currentProfile) {
2645 if (partsImageContents == null || partsManageData == null) {
2649 // 現在のプロファイルが所有する全パーツ一覧を構築する.
2651 HashSet<PartsIdentifier> currentProfilePartsIdentifiers = new HashSet<PartsIdentifier>();
2652 if (currentProfile != null) {
2653 for (PartsCategory partsCategory : currentProfile.getPartsCategories()) {
2654 currentProfilePartsIdentifiers.addAll(currentProfile.getPartsSpecMap(partsCategory).keySet());
2657 this.currentProfilePartsIdentifiers = Collections.unmodifiableSet(currentProfilePartsIdentifiers);
2659 // 同じパーツ名をもつ各レイヤーを集める
2660 HashMap<String, ImportPartsImageSet> partsImageSets = new HashMap<String, ImportPartsImageSet>();
2661 for (PartsImageContent content : partsImageContents) {
2662 String partsName = content.getPartsName();
2663 ImportPartsImageSet partsImageSet = partsImageSets.get(partsName);
2664 if (partsImageSet == null) {
2665 partsImageSet = new ImportPartsImageSet(partsName);
2666 partsImageSets.put(partsName, partsImageSet);
2668 partsImageSet.add(content);
2672 ArrayList<String> partsNames = new ArrayList<String>(partsImageSets.keySet());
2673 Collections.sort(partsNames);
2676 for (String partsName : partsNames) {
2677 ImportPartsImageSet partsImageSet = partsImageSets.get(partsName);
2678 int numOfLink = partsImageSet.getPartsCategories().size();
2679 for (PartsCategory partsCategory : partsImageSet.getPartsCategories()) {
2682 PartsManageData.PartsKey partsKey = new PartsManageData.PartsKey(partsName, partsCategory.getCategoryId());
2683 // ローカライズされたパーツ名があれば取得する。なければオリジナルのまま
2684 String localizedPartsName = partsManageData.getLocalizedName(partsKey);
2685 if (localizedPartsName == null || localizedPartsName.length() == 0) {
2686 localizedPartsName = partsName;
2688 // 作者情報・バージョン情報があれば取得する.
2689 PartsAuthorInfo partsAuthorInfo = partsManageData.getPartsAuthorInfo(partsKey);
2690 PartsManageData.PartsVersionInfo versionInfo = partsManageData.getVersion(partsKey);
2693 PartsIdentifier partsIdentifier = new PartsIdentifier(partsCategory, partsName, localizedPartsName);
2695 // 現在のプロファイル上のパーツ情報を取得する.(なければnull)
2696 PartsSpec partsSpec;
2697 if (currentProfile != null) {
2698 partsSpec = currentProfile.getPartsSpec(partsIdentifier);
2704 ImportPartsModel rowModel = new ImportPartsModel(
2705 partsIdentifier, partsAuthorInfo, versionInfo,
2706 partsSpec, partsImageSet, numOfLink);
2712 // 既存がないか、既存よりも新しい日付であれば自動的にチェックを設定する.
2713 // もしくはバージョンが上であれば自動的にチェックをつける.
2714 for (ImportPartsModel rowModel : elements) {
2716 // 現在のプロファイル上のファイル群の最終更新日
2717 Long lastModifiedAtCurrent = rowModel.getLastModifiedAtCurrentProfile();
2718 if (lastModifiedAtCurrent == null) {
2719 lastModifiedAtCurrent = Long.valueOf(0);
2722 // インポートするファイル群の最終更新日
2723 ImportPartsImageSet partsImageSet = rowModel.getImageSet();
2725 // 新しければ自動的にチェックをつける.
2726 if (lastModifiedAtCurrent.longValue() < partsImageSet.lastModified()) {
2727 partsImageSet.setChecked(true);
2730 // バージョンが新しければチェックをつける. (改変版や作者名改名もあるので、作者名が同一であるかは問わない.)
2731 double versionAtCurrent = rowModel.getVersionAtCurrent();
2732 double version = rowModel.getVersion();
2733 if (versionAtCurrent < version) {
2734 partsImageSet.setChecked(true);
2743 * 選択されているパーツを構成するファイルのコレクションを返します.<br>
2745 * @return パーツイメージコンテンツのコレクション、選択がなければ空
2747 public Collection<PartsImageContent> getSelectedPartsImageContents() {
2748 IdentityHashMap<ImportPartsImageSet, ImportPartsImageSet> partsImageSets
2749 = new IdentityHashMap<ImportPartsImageSet, ImportPartsImageSet>();
2751 for (ImportPartsModel rowModel : elements) {
2752 ImportPartsImageSet partsImageSet = rowModel.getImageSet();
2753 if (partsImageSet.isChecked()) {
2754 partsImageSets.put(partsImageSet, partsImageSet);
2758 ArrayList<PartsImageContent> partsImageContents = new ArrayList<PartsImageContent>();
2759 for (ImportPartsImageSet partsImageSet : partsImageSets.values()) {
2760 partsImageContents.addAll(partsImageSet);
2762 return partsImageContents;
2766 * 選択されているパーツ識別子のコレクションを返します.<br>
2767 * 返されるコレクションには同一のパーツ識別子が複数存在しないことが保証されます.<br>
2768 * 一つも選択がない場合は空が返されます.<br>
2770 * @return パーツ識別子のコレクション.<br>
2772 public Collection<PartsIdentifier> getSelectedPartsIdentifiers() {
2773 HashSet<PartsIdentifier> partsIdentifiers = new HashSet<PartsIdentifier>();
2774 for (ImportPartsModel rowModel : elements) {
2775 if (rowModel.isChecked()) {
2776 partsIdentifiers.add(rowModel.getPartsIdentifier());
2779 return partsIdentifiers;
2783 * 現在のプロファイルが所有している全パーツの識別子.<br>
2784 * 現在のプロファイルがないか、まったく所有していなければ空.<br>
2786 * @return 現在のプロファイルが所有するパーツの識別子のコレクション.(重複しない一意であることが保証される.)
2788 public Collection<PartsIdentifier> getCurrentProfilePartsIdentifers() {
2789 return currentProfilePartsIdentifiers;
2792 public int getColumnCount() {
2793 return COLUMN_NAMES.length;
2797 public String getColumnName(int column) {
2798 return COLUMN_NAMES[column];
2801 public Object getValueAt(int rowIndex, int columnIndex) {
2802 ImportPartsModel rowModel = getRow(rowIndex);
2803 switch (columnIndex) {
2805 return rowModel.isChecked();
2807 return rowModel.getPartsName();
2809 return rowModel.getPartsCategory().getLocalizedCategoryName();
2811 return rowModel.getWidth() + "x" + rowModel.getHeight()
2812 + (rowModel.isUnmatchedSize() ? "*" : "");
2814 return rowModel.isAlphaColor();
2816 long lastModified = rowModel.getLastModified();
2817 if (lastModified > 0) {
2818 return new Timestamp(lastModified).toString();
2822 Long lastModifiedAtCur = rowModel.getLastModifiedAtCurrentProfile();
2823 if (lastModifiedAtCur != null && lastModifiedAtCur.longValue() > 0) {
2824 return new Timestamp(lastModifiedAtCur.longValue()).toString();
2828 return rowModel.getAuthor();
2830 return rowModel.getAuthorAtCurrent();
2832 double version = rowModel.getVersion();
2834 return Double.toString(version);
2838 double versionAtCurrent = rowModel.getVersionAtCurrent();
2839 if (versionAtCurrent > 0) {
2840 return Double.toString(versionAtCurrent);
2848 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
2849 ImportPartsModel rowModel = getRow(rowIndex);
2851 switch (columnIndex) {
2853 rowModel.setChecked(((Boolean) aValue).booleanValue());
2859 if (rowModel.getNumOfLink() > 1) {
2860 fireTableDataChanged();
2862 fireListUpdated(rowIndex, rowIndex);
2867 public Class<?> getColumnClass(int columnIndex) {
2868 switch (columnIndex) {
2870 return Boolean.class;
2872 return String.class;
2874 return String.class;
2876 return String.class;
2878 return Boolean.class;
2880 return String.class;
2882 return String.class;
2884 return String.class;
2886 return String.class;
2888 return String.class;
2890 return String.class;
2892 return String.class;
2896 public boolean isCellEditable(int rowIndex, int columnIndex) {
2897 if (columnIndex == 0) {
2903 public void adjustColumnModel(TableColumnModel columnModel, double scale) {
2904 int mx = columnModel.getColumnCount();
2905 for (int idx = 0; idx < mx; idx++) {
2906 columnModel.getColumn(idx).setPreferredWidth((int)(COLUMN_WIDTHS[idx] * scale));
2910 public void selectAll() {
2911 boolean modified = false;
2912 for (ImportPartsModel rowModel : elements) {
2913 if (!rowModel.isChecked()) {
2914 rowModel.setChecked(true);
2919 fireTableDataChanged();
2923 public void deselectAll() {
2924 boolean modified = false;
2925 for (ImportPartsModel rowModel : elements) {
2926 if (rowModel.isChecked()) {
2927 rowModel.setChecked(false);
2932 fireTableDataChanged();
2936 public void sort() {
2937 Collections.sort(elements, new Comparator<ImportPartsModel> () {
2938 public int compare(ImportPartsModel o1, ImportPartsModel o2) {
2939 int ret = (o1.isChecked() ? 0 : 1) - (o2.isChecked() ? 0 : 1);
2941 ret = o1.getPartsIdentifier().compareTo(o2.getPartsIdentifier());
2947 fireTableDataChanged();
2950 public void sortByTimestamp() {
2951 Collections.sort(elements, new Comparator<ImportPartsModel> () {
2952 public int compare(ImportPartsModel o1, ImportPartsModel o2) {
2953 long ret = (o1.isChecked() ? 0 : 1) - (o2.isChecked() ? 0 : 1);
2955 Long tm1 = o1.getLastModifiedAtCurrentProfile();
2956 Long tm2 = o2.getLastModifiedAtCurrentProfile();
2958 long lastModified1 = Math.max(o1.getLastModified(), tm1 == null ? 0 : tm1.longValue());
2959 long lastModified2 = Math.max(o2.getLastModified(), tm2 == null ? 0 : tm2.longValue());
2961 ret = lastModified1 - lastModified2;
2964 ret = o1.getPartsIdentifier().compareTo(o2.getPartsIdentifier());
2967 return ret == 0 ? 0 : ret > 0 ? 1 : -1;
2971 fireTableDataChanged();
2975 * 指定したパーツ識別子をチェック状態にする.
2977 * @param partsIdentifiers
2978 * パーツ識別子のコレクション、nullの場合は何もしない.
2980 public void selectByPartsIdentifiers(Collection<PartsIdentifier> partsIdentifiers) {
2981 boolean modified = false;
2982 if (partsIdentifiers != null) {
2983 for (PartsIdentifier partsIdentifier : partsIdentifiers) {
2984 for (ImportPartsModel rowModel : elements) {
2985 if (rowModel.getPartsIdentifier().equals(partsIdentifier)) {
2986 if (!rowModel.isChecked()) {
2987 rowModel.setChecked(true);
2995 fireTableDataChanged();
2999 public void setCheck(int[] selRows, boolean checked) {
3000 if (selRows == null || selRows.length == 0) {
3003 Arrays.sort(selRows);
3004 for (int selRow : selRows) {
3005 ImportPartsModel rowModel = getRow(selRow);
3006 rowModel.setChecked(checked);
3008 fireTableRowsUpdated(selRows[0], selRows[selRows.length - 1]);
3019 class ImportPresetSelectPanel extends ImportWizardCardPanel {
3021 private static final long serialVersionUID = 1L;
3023 public static final String PANEL_NAME = "importPresetSelectPanel";
3025 private ImportPresetTableModel presetTableModel;
3027 private ImportWizardDialog parent;
3029 private JTable presetTable;
3031 private Action actSelectAll;
3033 private Action actDeselectAll;
3035 private Action actSelectUsedParts;
3037 public ImportPresetSelectPanel(ScaleSupport scaleSupport) {
3038 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
3039 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
3041 setBorder(BorderFactory.createTitledBorder(strings.getProperty("preset.title")));
3043 setLayout(new BorderLayout());
3045 presetTableModel = new ImportPresetTableModel();
3047 presetTableModel.addTableModelListener(new TableModelListener() {
3048 public void tableChanged(TableModelEvent e) {
3049 if (e.getType() == TableModelEvent.UPDATE) {
3055 AppConfig appConfig = AppConfig.getInstance();
3056 final Color warningForegroundColor = appConfig.getExportPresetWarningsForegroundColor();
3057 final Color disabledForeground = appConfig.getDisabledCellForgroundColor();
3059 presetTable = new JTable(presetTableModel) {
3060 private static final long serialVersionUID = 1L;
3063 public Component prepareRenderer(TableCellRenderer renderer,
3064 int row, int column) {
3065 Component comp = super.prepareRenderer(renderer, row, column);
3067 if (comp instanceof JCheckBox) {
3068 // BooleanのデフォルトのレンダラーはJCheckBoxを継承したJTable$BooleanRenderer
3069 comp.setEnabled(isCellEditable(row, column) && isEnabled());
3072 ImportPresetModel presetModel = presetTableModel.getRow(row);
3074 // インポート先のプリセットを上書きする場合、もしくはデフォルトのパーツセットの場合は太字にする.
3075 if (presetModel.isOverwrite() || presetTableModel.isDefaultPartsSet(row)) {
3076 comp.setFont(getFont().deriveFont(Font.BOLD));
3078 comp.setFont(getFont());
3081 // インポートするプリセットのパーツが不足している場合、警告色にする.
3083 comp.setForeground(disabledForeground);
3086 if (presetModel.isCheched()
3087 && presetModel.getMissingPartsIdentifiers().size() > 0) {
3088 comp.setForeground(warningForegroundColor);
3090 comp.setForeground(getForeground());
3096 presetTable.setShowGrid(true);
3097 presetTable.setGridColor(appConfig.getGridColor());
3098 presetTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
3101 presetTable.setRowHeight((int)(presetTable.getFont().getSize() * 1.2));
3103 actSelectUsedParts = new AbstractAction(strings.getProperty("preset.popup.selectUsedParts")) {
3104 private static final long serialVersionUID = 1L;
3106 public void actionPerformed(ActionEvent e) {
3111 final JPopupMenu popupMenu = new JPopupMenu();
3112 popupMenu.add(actSelectUsedParts);
3114 presetTable.setComponentPopupMenu(popupMenu);
3117 presetTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
3118 presetTableModel.adjustColumnModel(presetTable.getColumnModel(), scaleSupport.getManualScaleX());
3120 add(new JScrollPane(presetTable), BorderLayout.CENTER);
3122 actSelectAll = new AbstractAction(strings.getProperty("parts.btn.selectAll")) {
3123 private static final long serialVersionUID = 1L;
3125 public void actionPerformed(ActionEvent e) {
3129 actDeselectAll = new AbstractAction(strings.getProperty("parts.btn.deselectAll")) {
3130 private static final long serialVersionUID = 1L;
3132 public void actionPerformed(ActionEvent e) {
3136 Action actSort = new AbstractAction(strings
3137 .getProperty("parts.btn.sort")) {
3138 private static final long serialVersionUID = 1L;
3140 public void actionPerformed(ActionEvent e) {
3145 JPanel btnPanel = new JPanel();
3146 GridBagLayout btnPanelLayout = new GridBagLayout();
3147 btnPanel.setLayout(btnPanelLayout);
3149 GridBagConstraints gbc = new GridBagConstraints();
3155 gbc.anchor = GridBagConstraints.EAST;
3156 gbc.fill = GridBagConstraints.BOTH;
3157 int gap = (int)(3 * scaleSupport.getManualScaleX());
3158 gbc.insets = new Insets(gap, gap, gap, gap);
3161 JButton btnSelectAll = new JButton(actSelectAll);
3162 btnPanel.add(btnSelectAll, gbc);
3166 JButton btnDeselectAll = new JButton(actDeselectAll);
3167 btnPanel.add(btnDeselectAll, gbc);
3171 JButton btnSort = new JButton(actSort);
3172 btnPanel.add(btnSort, gbc);
3177 btnPanel.add(Box.createHorizontalGlue(), gbc);
3179 add(btnPanel, BorderLayout.SOUTH);
3183 public void onActive(ImportWizardDialog parent,
3184 ImportWizardCardPanel previousPanel) {
3185 this.parent= parent;
3187 actSelectUsedParts.setEnabled(parent.importTypeSelectPanel.isImportPartsImages());
3188 checkMissingParts();
3191 public void checkMissingParts() {
3192 Collection<PartsIdentifier> importedPartsIdentifiers = this.parent.importPartsSelectPanel.getImportedPartsIdentifiers();
3193 presetTableModel.checkMissingParts(importedPartsIdentifiers);
3196 protected void onSelectAll() {
3197 presetTableModel.selectAll();
3200 protected void onDeselectAll() {
3201 presetTableModel.deselectAll();
3204 protected void onSort() {
3205 presetTableModel.sort();
3206 if (presetTableModel.getRowCount() > 0) {
3207 Rectangle rct = presetTable.getCellRect(0, 0, true);
3208 presetTable.scrollRectToVisible(rct);
3212 protected void exportUsedParts() {
3213 ArrayList<PartsIdentifier> requirePartsIdentifiers = new ArrayList<PartsIdentifier>();
3214 int[] selRows = presetTable.getSelectedRows();
3215 for (int selRow : selRows) {
3216 ImportPresetModel presetModel = presetTableModel.getRow(selRow);
3217 PartsSet partsSet = presetModel.getPartsSet();
3218 for (List<PartsIdentifier> partsIdentifiers : partsSet.values()) {
3219 for (PartsIdentifier partsIdentifier : partsIdentifiers) {
3220 requirePartsIdentifiers.add(partsIdentifier);
3224 this.parent.importPartsSelectPanel.selectByPartsIdentifiers(requirePartsIdentifiers);
3225 checkMissingParts();
3229 public boolean isReadyPrevious() {
3234 public boolean isReadyNext() {
3239 public boolean isReadyFinish() {
3240 if (this.parent != null) {
3247 public String doPrevious() {
3249 return ImportPartsSelectPanel.PANEL_NAME;
3253 public String doNext() {
3257 public Collection<PartsSet> getSelectedPartsSets() {
3258 return presetTableModel.getSelectedPartsSets();
3262 * デフォルトのパーツセットIDとして使用されることが推奨されるパーツセットIDを取得する.<br>
3263 * 明示的なデフォルトのパーツセットIDがなければ、もしくは、 明示的に指定されているパーツセットIDが選択されているパーツセットの中になければ、
3264 * 選択されているパーツセットの最初のアイテムを返す.<br>
3265 * 選択しているパーツセットが一つもなければnullを返す.<br>
3267 * @return デフォルトのパーツセット
3269 public String getPrefferedDefaultPartsSetId() {
3270 String defaultPartsSetId = presetTableModel.getDefaultPartsSetId();
3271 String firstPartsSetId = null;
3272 boolean existsDefaultPartsSetId = false;
3273 for (PartsSet partsSet : getSelectedPartsSets()) {
3274 if (firstPartsSetId == null) {
3275 firstPartsSetId = partsSet.getPartsSetId();
3277 if (partsSet.getPartsSetId().equals(defaultPartsSetId)) {
3278 existsDefaultPartsSetId = true;
3281 if (!existsDefaultPartsSetId || defaultPartsSetId == null || defaultPartsSetId.length() == 0) {
3282 defaultPartsSetId = firstPartsSetId;
3284 return defaultPartsSetId;
3287 public void initModel(Collection<PartsSet> partsSets, String defaultPartsSetId, CharacterData presetImportTarget,
3288 boolean selectAll) {
3289 presetTableModel.initModel(partsSets, defaultPartsSetId, presetImportTarget);
3291 presetTableModel.selectAll();
3296 class ImportPresetModel {
3298 private boolean cheched;
3300 private PartsSet partsSet;
3302 private boolean overwrite;
3304 private Collection<PartsIdentifier> missingPartsIdentifiers = Collections.emptySet();
3306 public ImportPresetModel(PartsSet partsSet, boolean overwrite, boolean checked) {
3307 if (partsSet == null) {
3308 throw new IllegalArgumentException();
3310 this.partsSet = partsSet;
3311 this.cheched = checked;
3312 this.overwrite = overwrite;
3315 public boolean isCheched() {
3319 public void setCheched(boolean cheched) {
3320 this.cheched = cheched;
3323 public PartsSet getPartsSet() {
3327 public String getPartsSetName() {
3328 return partsSet.getLocalizedName();
3331 public void setPartsSetName(String name) {
3332 if (name == null || name.trim().length() == 0) {
3333 throw new IllegalArgumentException();
3335 partsSet.setLocalizedName(name);
3338 public Collection<PartsIdentifier> getMissingPartsIdentifiers() {
3339 return missingPartsIdentifiers;
3342 public boolean hasMissingParts() {
3346 public boolean isOverwrite() {
3350 public boolean checkMissingParts(Collection<PartsIdentifier> importedPartsIdentifiers) {
3351 HashSet<PartsIdentifier> missingPartsIdentifiers = new HashSet<PartsIdentifier>();
3352 for (List<PartsIdentifier> partsIdentifiers : partsSet.values()) {
3353 for (PartsIdentifier partsIdentifier : partsIdentifiers) {
3354 boolean exists = false;
3355 if (importedPartsIdentifiers != null && importedPartsIdentifiers.contains(partsIdentifier)) {
3359 missingPartsIdentifiers.add(partsIdentifier);
3364 boolean modified = (!missingPartsIdentifiers.equals(this.missingPartsIdentifiers));
3366 this.missingPartsIdentifiers = missingPartsIdentifiers;
3372 class ImportPresetTableModel extends AbstractTableModelWithComboBoxModel<ImportPresetModel> {
3374 private static final long serialVersionUID = 1L;
3376 private static final String[] COLUMN_NAMES; // = {"選択", "プリセット名",
3379 private static final int[] COLUMN_WIDTHS; // = {50, 100, 200};
3382 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
3383 .getLocalizedProperties(ImportWizardDialog.STRINGS_RESOURCE);
3385 COLUMN_NAMES = new String[] {
3386 strings.getProperty("preset.column.check"),
3387 strings.getProperty("preset.column.name"),
3388 strings.getProperty("preset.column.missings"),
3391 COLUMN_WIDTHS = new int[] {
3392 Integer.parseInt(strings.getProperty("preset.column.check.size")),
3393 Integer.parseInt(strings.getProperty("preset.column.name.size")),
3394 Integer.parseInt(strings.getProperty("preset.column.missings.size")),
3398 private String defaultPartsSetId;
3400 public String getDefaultPartsSetId() {
3401 return defaultPartsSetId;
3404 public void setDefaultPartsSetId(String defaultPartsSetId) {
3405 this.defaultPartsSetId = defaultPartsSetId;
3408 public int getColumnCount() {
3409 return COLUMN_NAMES.length;
3413 public String getColumnName(int column) {
3414 return COLUMN_NAMES[column];
3418 public Class<?> getColumnClass(int columnIndex) {
3419 switch (columnIndex) {
3421 return Boolean.class;
3423 return String.class;
3425 return String.class;
3427 return String.class;
3431 public boolean isCellEditable(int rowIndex, int columnIndex) {
3432 if (columnIndex == 0 || columnIndex == 1) {
3438 public Object getValueAt(int rowIndex, int columnIndex) {
3439 ImportPresetModel rowModel = getRow(rowIndex);
3440 switch (columnIndex) {
3442 return rowModel.isCheched();
3444 return rowModel.getPartsSetName();
3446 return getMissingPartsIdentifiersString(rowModel);
3451 private String getMissingPartsIdentifiersString(ImportPresetModel rowModel) {
3452 StringBuilder buf = new StringBuilder();
3453 for (PartsIdentifier partsIdentifier : rowModel.getMissingPartsIdentifiers()) {
3454 if (buf.length() > 0) {
3457 buf.append(partsIdentifier.getLocalizedPartsName());
3459 return buf.toString();
3463 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
3464 ImportPresetModel rowModel = getRow(rowIndex);
3465 switch (columnIndex) {
3467 rowModel.setCheched(((Boolean) aValue).booleanValue());
3470 String name = (String) aValue;
3471 name = (name != null) ? name.trim() : "";
3472 if (name.length() > 0) {
3473 rowModel.setPartsSetName(name);
3478 fireTableRowsUpdated(rowIndex, rowIndex);
3482 * 指定した行のパーツセットがデフォルトパーツセットであるか?
3486 * @return デフォルトパーツセットであればtrue、そうでなければfalse
3488 public boolean isDefaultPartsSet(int rowIndex) {
3489 ImportPresetModel rowModel = getRow(rowIndex);
3490 return rowModel.getPartsSet().getPartsSetId().equals(defaultPartsSetId);
3493 public void adjustColumnModel(TableColumnModel columnModel, double scale) {
3494 int mx = columnModel.getColumnCount();
3495 for (int idx = 0; idx < mx; idx++) {
3496 columnModel.getColumn(idx).setPreferredWidth((int)(COLUMN_WIDTHS[idx] * scale));
3501 * パーツセットリストを構築する.<br>
3505 * @param defaultPartsSetId
3506 * デフォルトのパーツセットID、なければnull
3507 * @param presetImportTarget
3508 * インポート先、新規の場合はnull (上書き判定のため)
3510 public void initModel(Collection<PartsSet> partsSets, String defaultPartsSetId, CharacterData presetImportTarget) {
3512 if (partsSets == null) {
3517 Map<String, PartsSet> currentProfilesPartsSet;
3518 if (presetImportTarget != null) {
3519 currentProfilesPartsSet = presetImportTarget.getPartsSets();
3521 // 新規の場合は既存パーツセットは空.
3522 currentProfilesPartsSet = Collections.emptyMap();
3525 // インポートもとのパーツセットをテープルモデルに登録する.
3526 for (PartsSet partsSet : partsSets) {
3527 String partsSetId = partsSet.getPartsSetId();
3528 if (partsSetId == null || partsSetId.length() == 0) {
3531 PartsSet compatiblePartsSet;
3532 if (presetImportTarget != null) {
3533 // 既存のキャラクター定義へのインポート時は、パーツセットのカテゴリを合わせる.
3534 // 一つもカテゴリが合わない場合は空のパーツセットになる.
3535 compatiblePartsSet = partsSet.createCompatible(presetImportTarget);
3537 compatiblePartsSet = partsSet; // 新規の場合はフィッティングの必要なし.
3539 if (!compatiblePartsSet.isEmpty()) {
3540 // 空のパーツセットは登録対象にしない.
3541 boolean overwrite = currentProfilesPartsSet.containsKey(partsSetId);
3542 boolean checked = (presetImportTarget == null); // 新規の場合は既定で選択状態とする.
3543 ImportPresetModel rowModel = new ImportPresetModel(partsSet, overwrite, checked);
3548 // デフォルトのパーツセットIDを設定、存在しない場合はnull
3549 this.defaultPartsSetId = defaultPartsSetId;
3554 public Collection<PartsSet> getSelectedPartsSets() {
3555 ArrayList<PartsSet> partsSets = new ArrayList<PartsSet>();
3556 for (ImportPresetModel rowModel : elements) {
3557 if (rowModel.isCheched()) {
3558 partsSets.add(rowModel.getPartsSet());
3564 public void selectAll() {
3565 boolean modified = false;
3566 for (ImportPresetModel rowModel : elements) {
3567 if (!rowModel.isCheched()) {
3568 rowModel.setCheched(true);
3573 fireTableDataChanged();
3577 public void deselectAll() {
3578 boolean modified = false;
3579 for (ImportPresetModel rowModel : elements) {
3580 if (rowModel.isCheched()) {
3581 rowModel.setCheched(false);
3586 fireTableDataChanged();
3590 public void sort() {
3591 Collections.sort(elements, new Comparator<ImportPresetModel>() {
3592 public int compare(ImportPresetModel o1, ImportPresetModel o2) {
3593 int ret = (o1.isCheched() ? 0 : 1) - (o2.isCheched() ? 0 : 1);
3595 ret = o1.getPartsSetName().compareTo(o2.getPartsSetName());
3600 fireTableDataChanged();
3603 public void checkMissingParts(Collection<PartsIdentifier> importedPartsIdentifiers) {
3604 boolean changed = false;
3606 for (ImportPresetModel rowModel : elements) {
3607 if (rowModel.checkMissingParts(importedPartsIdentifiers)) {
3613 fireTableDataChanged();