1 package charactermanaj.ui;
\r
3 import java.awt.BorderLayout;
\r
4 import java.awt.Color;
\r
5 import java.awt.Component;
\r
6 import java.awt.Container;
\r
7 import java.awt.GridBagConstraints;
\r
8 import java.awt.GridBagLayout;
\r
9 import java.awt.Insets;
\r
10 import java.awt.Toolkit;
\r
11 import java.awt.event.ActionEvent;
\r
12 import java.awt.event.KeyEvent;
\r
13 import java.awt.event.MouseEvent;
\r
14 import java.awt.event.WindowAdapter;
\r
15 import java.awt.event.WindowEvent;
\r
16 import java.io.File;
\r
17 import java.util.Collections;
\r
18 import java.util.EnumSet;
\r
19 import java.util.Properties;
\r
20 import java.util.Set;
\r
21 import java.util.logging.Level;
\r
22 import java.util.logging.Logger;
\r
24 import javax.swing.AbstractAction;
\r
25 import javax.swing.Action;
\r
26 import javax.swing.ActionMap;
\r
27 import javax.swing.BorderFactory;
\r
28 import javax.swing.Box;
\r
29 import javax.swing.InputMap;
\r
30 import javax.swing.JButton;
\r
31 import javax.swing.JCheckBox;
\r
32 import javax.swing.JComponent;
\r
33 import javax.swing.JDialog;
\r
34 import javax.swing.JFrame;
\r
35 import javax.swing.JLabel;
\r
36 import javax.swing.JOptionPane;
\r
37 import javax.swing.JPanel;
\r
38 import javax.swing.JRootPane;
\r
39 import javax.swing.JScrollPane;
\r
40 import javax.swing.JTable;
\r
41 import javax.swing.KeyStroke;
\r
42 import javax.swing.table.TableCellRenderer;
\r
43 import javax.swing.table.TableColumnModel;
\r
45 import charactermanaj.Main;
\r
46 import charactermanaj.model.AppConfig;
\r
47 import charactermanaj.ui.model.AbstractTableModelWithComboBoxModel;
\r
48 import charactermanaj.util.ConfigurationDirUtilities;
\r
49 import charactermanaj.util.DesktopUtilities;
\r
50 import charactermanaj.util.ErrorMessageHelper;
\r
51 import charactermanaj.util.LocalizedResourcePropertyLoader;
\r
52 import charactermanaj.util.SetupLocalization;
\r
60 public class AppConfigDialog extends JDialog {
\r
62 private static final long serialVersionUID = 1L;
\r
64 private static final Logger logger = Logger.getLogger(AppConfigDialog.class.getName());
\r
66 private AppConfigTableModel appConfigTableModel;
\r
68 private JTable appConfigTable;
\r
70 private JCheckBox chkResetDoNotAskAgain;
\r
72 private RecentCharactersDir recentCharactersDir;
\r
74 public AppConfigDialog(JFrame parent) {
\r
75 super(parent, true);
\r
77 setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
\r
78 addWindowListener(new WindowAdapter() {
\r
80 public void windowClosing(WindowEvent e) {
\r
89 } catch (RuntimeException ex) {
\r
90 logger.log(Level.SEVERE, "appConfig construct failed.", ex);
\r
96 private void initComponent() {
\r
98 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
\r
99 .getLocalizedProperties("languages/appconfigdialog");
\r
101 setTitle(strings.getProperty("title"));
\r
103 Container contentPane = getContentPane();
\r
104 contentPane.setLayout(new BorderLayout());
\r
107 JPanel btnPanel = new JPanel();
\r
108 btnPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 45));
\r
109 GridBagLayout btnPanelLayout = new GridBagLayout();
\r
110 btnPanel.setLayout(btnPanelLayout);
\r
112 GridBagConstraints gbc = new GridBagConstraints();
\r
114 Action actApply = new AbstractAction(strings.getProperty("btn.apply")) {
\r
115 private static final long serialVersionUID = 1L;
\r
116 public void actionPerformed(ActionEvent e) {
\r
120 Action actCancel = new AbstractAction(strings.getProperty("btn.cancel")) {
\r
121 private static final long serialVersionUID = 1L;
\r
122 public void actionPerformed(ActionEvent e) {
\r
126 Action actLocalization = new AbstractAction(strings.getProperty("btn.setupLocalization")) {
\r
127 private static final long serialVersionUID = 1L;
\r
128 public void actionPerformed(ActionEvent e) {
\r
129 onSetupLocalization();
\r
133 chkResetDoNotAskAgain = new JCheckBox(strings.getProperty("chk.askForCharactersDir"));
\r
137 gbc.gridheight = 1;
\r
139 gbc.anchor = GridBagConstraints.WEST;
\r
140 gbc.fill = GridBagConstraints.NONE;
\r
141 gbc.insets = new Insets(0, 0, 0, 0);
\r
146 btnPanel.add(chkResetDoNotAskAgain, gbc);
\r
150 gbc.gridheight = 1;
\r
152 gbc.anchor = GridBagConstraints.WEST;
\r
153 gbc.fill = GridBagConstraints.NONE;
\r
154 gbc.insets = new Insets(3, 3, 3, 3);
\r
159 btnPanel.add(new JButton(actLocalization), gbc);
\r
163 gbc.gridheight = 1;
\r
165 gbc.fill = GridBagConstraints.BOTH;
\r
168 btnPanel.add(Box.createHorizontalGlue(), gbc);
\r
170 gbc.gridx = Main.isLinuxOrMacOSX() ? 2 : 1;
\r
172 JButton btnApply = new JButton(actApply);
\r
173 btnPanel.add(btnApply, gbc);
\r
175 gbc.gridx = Main.isLinuxOrMacOSX() ? 1 : 2;
\r
177 JButton btnCancel = new JButton(actCancel);
\r
178 btnPanel.add(btnCancel, gbc);
\r
180 add(btnPanel, BorderLayout.SOUTH);
\r
183 setLocationRelativeTo(getParent());
\r
186 JLabel lblCaution = new JLabel(strings.getProperty("caution"), JLabel.CENTER);
\r
187 lblCaution.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
\r
188 lblCaution.setForeground(Color.red);
\r
189 contentPane.add(lblCaution, BorderLayout.NORTH);
\r
192 appConfigTableModel = new AppConfigTableModel();
\r
195 AppConfig appConfig = AppConfig.getInstance();
\r
196 final Color invalidBgColor = appConfig.getInvalidBgColor();
\r
197 appConfigTable = new JTable(appConfigTableModel) {
\r
198 private static final long serialVersionUID = 1L;
\r
200 public Component prepareRenderer(TableCellRenderer renderer,
\r
201 int row, int column) {
\r
202 Component comp = super.prepareRenderer(renderer, row, column);
\r
203 AppConfigRowModel rowModel = appConfigTableModel.getRow(row);
\r
204 if (rowModel.isRejected()) {
\r
205 comp.setBackground(invalidBgColor);
\r
207 if (isCellSelected(row, column)) {
\r
208 comp.setBackground(getSelectionBackground());
\r
210 comp.setBackground(getBackground());
\r
216 public String getToolTipText(MouseEvent event) {
\r
217 int row = rowAtPoint(event.getPoint());
\r
218 int col = columnAtPoint(event.getPoint());
\r
220 AppConfigRowModel rowModel = appConfigTableModel.getRow(row);
\r
221 return rowModel.getDisplayName();
\r
223 return super.getToolTipText(event);
\r
226 appConfigTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
\r
227 appConfigTable.setShowGrid(true);
\r
228 appConfigTable.setGridColor(AppConfig.getInstance().getGridColor());
\r
229 appConfigTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
\r
230 appConfigTableModel.adjustColumnModel(appConfigTable.getColumnModel());
\r
231 JScrollPane appConfigTableSP = new JScrollPane(appConfigTable);
\r
232 appConfigTableSP.setBorder(BorderFactory.createCompoundBorder(
\r
233 BorderFactory.createEmptyBorder(0, 3, 0, 3),
\r
234 BorderFactory.createTitledBorder(strings.getProperty("table.caption")))
\r
236 appConfigTableSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
\r
237 contentPane.add(appConfigTableSP, BorderLayout.CENTER);
\r
240 Toolkit tk = Toolkit.getDefaultToolkit();
\r
241 JRootPane rootPane = getRootPane();
\r
242 InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
\r
243 ActionMap am = rootPane.getActionMap();
\r
244 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "closeAppConfigDialog");
\r
245 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, tk.getMenuShortcutKeyMask()), "closeAppConfigDialog");
\r
246 am.put("closeAppConfigDialog", actCancel);
\r
248 // 保存先が無効であれば適用ボタンを有効にしない.
\r
249 boolean enableSave = !appConfig.getPrioritySaveFileList().isEmpty();
\r
250 btnApply.setEnabled(enableSave);
\r
253 private void loadData() {
\r
254 Properties original = AppConfig.getInstance().getProperties();
\r
255 appConfigTableModel.initModel(original);
\r
258 recentCharactersDir = RecentCharactersDir.load();
\r
260 if (recentCharactersDir != null) {
\r
261 File lastUseCharactersDir = recentCharactersDir.getLastUseCharacterDir();
\r
262 boolean enableLastUseCharacterDir = lastUseCharactersDir != null && lastUseCharactersDir.isDirectory();
\r
263 boolean doNotAskAgain = enableLastUseCharacterDir && recentCharactersDir.isDoNotAskAgain();
\r
264 chkResetDoNotAskAgain.setEnabled(enableLastUseCharacterDir);
\r
265 chkResetDoNotAskAgain.setSelected(!doNotAskAgain);
\r
268 } catch (Exception ex) {
\r
269 recentCharactersDir = null;
\r
270 logger.log(Level.WARNING, "RecentCharactersDir load failed.", ex);
\r
275 * ローカライズリソースをユーザディレクトリ上に展開する.
\r
277 protected void onSetupLocalization() {
\r
278 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
\r
279 .getLocalizedProperties("languages/appconfigdialog");
\r
280 if (JOptionPane.showConfirmDialog(this,
\r
281 strings.getProperty("setupLocalization"),
\r
282 strings.getProperty("confirm.setupLocalization.caption"),
\r
283 JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) {
\r
288 File baseDir = ConfigurationDirUtilities.getUserDataDir();
\r
289 SetupLocalization setup = new SetupLocalization(baseDir);
\r
290 setup.setupToLocal(
\r
291 EnumSet.allOf(SetupLocalization.Resources.class), true);
\r
293 File resourceDir = setup.getResourceDir();
\r
294 DesktopUtilities.open(resourceDir);
\r
296 } catch (Exception ex) {
\r
297 ErrorMessageHelper.showErrorDialog(this, ex);
\r
301 protected void onClose() {
\r
302 if (appConfigTableModel.isModified()) {
\r
303 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
\r
304 .getLocalizedProperties("languages/appconfigdialog");
\r
305 if (JOptionPane.showConfirmDialog(this, strings.getProperty("confirm.close"),
\r
306 strings.getProperty("confirm.close.caption"), JOptionPane.YES_NO_OPTION,
\r
307 JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION) {
\r
314 protected void onUpdate() {
\r
316 if (appConfigTable.isEditing()) {
\r
318 Toolkit tk = Toolkit.getDefaultToolkit();
\r
323 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
\r
324 .getLocalizedProperties("languages/appconfigdialog");
\r
326 // 編集されたプロパティを取得する.
\r
327 Properties props = appConfigTableModel.getProperties();
\r
329 // 編集されたプロパティが適用可能か検証する.
\r
330 Set<String> rejectNames = AppConfig.checkProperties(props);
\r
331 if (!rejectNames.isEmpty()) {
\r
333 appConfigTableModel.setRejectNames(rejectNames);
\r
335 JOptionPane.showMessageDialog(this, strings.getProperty("error.message"),
\r
336 strings.getProperty("error.caption"), JOptionPane.ERROR_MESSAGE);
\r
341 // アプリケーション設定を更新し、保存する.
\r
342 AppConfig appConfig = AppConfig.getInstance();
\r
343 appConfig.update(props);
\r
344 appConfig.saveConfig();
\r
346 // キャラクターデータディレクトリの起動時の選択
\r
347 if (chkResetDoNotAskAgain.isEnabled()) {
\r
348 boolean doNotAskAgain = !chkResetDoNotAskAgain.isSelected();
\r
349 if (doNotAskAgain != recentCharactersDir.isDoNotAskAgain()) {
\r
350 recentCharactersDir.setDoNotAskAgain(doNotAskAgain);
\r
351 recentCharactersDir.saveRecents();
\r
355 } catch (Exception ex) {
\r
356 ErrorMessageHelper.showErrorDialog(this, ex);
\r
360 // アプリケーションの再起動が必要なことを示すダイアログを表示する.
\r
361 String message = strings.getProperty("caution");
\r
362 JOptionPane.showMessageDialog(this, message);
\r
369 class AppConfigRowModel implements Comparable<AppConfigRowModel> {
\r
371 private Properties target;
\r
373 private String key;
\r
375 private String displayName;
\r
377 private boolean rejected;
\r
379 public AppConfigRowModel(Properties target, String key, String displayName) {
\r
380 this.target = target;
\r
382 this.displayName = displayName;
\r
386 public int hashCode() {
\r
387 return key == null ? 0 : key.hashCode();
\r
391 public boolean equals(Object obj) {
\r
395 if (obj != null && obj instanceof AppConfigRowModel) {
\r
396 AppConfigRowModel o = (AppConfigRowModel) obj;
\r
397 return key == null ? o.key == null : key.equals(o.key);
\r
402 public int compareTo(AppConfigRowModel o) {
\r
406 int ret = displayName.compareTo(o.displayName);
\r
408 ret = key.compareTo(o.key);
\r
413 public String getKey() {
\r
417 public void setValue(String value) {
\r
418 if (value == null) {
\r
421 target.setProperty(key, value);
\r
424 public String getValue() {
\r
425 return target.getProperty(key);
\r
428 public String getDisplayName() {
\r
429 int sep = displayName.indexOf(';');
\r
431 return displayName.substring(sep + 1);
\r
433 return displayName;
\r
436 public boolean isRejected() {
\r
440 public void setRejected(boolean rejected) {
\r
441 this.rejected = rejected;
\r
445 class AppConfigTableModel extends AbstractTableModelWithComboBoxModel<AppConfigRowModel> {
\r
447 private static final long serialVersionUID = 1L;
\r
449 private static final String[] COLUMN_NAMES;
\r
451 private static final int[] COLUMN_WIDTHS;
\r
453 private Properties target = new Properties();
\r
455 private Properties original;
\r
458 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
\r
459 .getLocalizedProperties("languages/appconfigdialog");
\r
461 COLUMN_NAMES = new String[] {
\r
462 strings.getProperty("column.key"),
\r
463 strings.getProperty("column.value"),
\r
465 COLUMN_WIDTHS = new int[] {
\r
466 Integer.parseInt(strings.getProperty("column.key.width")),
\r
467 Integer.parseInt(strings.getProperty("column.value.width")),
\r
471 public void initModel(Properties original) {
\r
475 this.original = original;
\r
476 if (original != null) {
\r
477 target.putAll(original);
\r
479 Properties strings = LocalizedResourcePropertyLoader.getCachedInstance()
\r
480 .getLocalizedProperties("languages/appconfigdialog");
\r
482 for (Object key : target.keySet()) {
\r
483 String displayName = strings.getProperty((String) key);
\r
484 if (displayName == null || displayName.length() == 0) {
\r
485 displayName = (String) key;
\r
488 AppConfigRowModel rowModel = new AppConfigRowModel(target, (String) key, displayName);
\r
496 public void sort() {
\r
497 Collections.sort(elements);
\r
498 fireTableDataChanged();
\r
501 public void setRejectNames(Set<String> rejectNames) {
\r
502 for (AppConfigRowModel rowModel : elements) {
\r
503 String key = rowModel.getKey();
\r
504 boolean rejected = (rejectNames != null && rejectNames.contains(key));
\r
505 rowModel.setRejected(rejected);
\r
507 fireTableDataChanged();
\r
513 * @return 編集されていればtrue、そうでなければfalse
\r
515 public boolean isModified() {
\r
516 if (original == null) {
\r
519 return !original.equals(target);
\r
522 public Properties getProperties() {
\r
527 public int getColumnCount() {
\r
528 return COLUMN_NAMES.length;
\r
532 public Class<?> getColumnClass(int columnIndex) {
\r
533 return String.class;
\r
537 public String getColumnName(int column) {
\r
538 return COLUMN_NAMES[column];
\r
542 public boolean isCellEditable(int rowIndex, int columnIndex) {
\r
543 if (columnIndex == 1) {
\r
549 public Object getValueAt(int rowIndex, int columnIndex) {
\r
550 AppConfigRowModel rowModel = getRow(rowIndex);
\r
551 switch (columnIndex) {
\r
553 return rowModel.getDisplayName();
\r
555 return rowModel.getValue();
\r
561 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
\r
562 AppConfigRowModel rowModel = getRow(rowIndex);
\r
563 if (columnIndex == 1) {
\r
564 rowModel.setValue((String) aValue);
\r
565 fireTableCellUpdated(rowIndex, columnIndex);
\r
569 public void adjustColumnModel(TableColumnModel columnModel) {
\r
570 int mx = columnModel.getColumnCount();
\r
571 for (int idx = 0; idx < mx; idx++) {
\r
572 columnModel.getColumn(idx).setWidth(COLUMN_WIDTHS[idx]);
\r