diff --git a/docs/api/versions/latest b/docs/api/versions/latest new file mode 100644 index 00000000..b268c925 --- /dev/null +++ b/docs/api/versions/latest @@ -0,0 +1,4 @@ +{ + "version": "0.26.2", + "releasedAt": "2025-08-31", +} \ No newline at end of file diff --git "a/xyz.hotchpotch.hogandiff/messages.properties\347\256\241\347\220\206.xlsx" "b/xyz.hotchpotch.hogandiff/messages.properties\347\256\241\347\220\206.xlsx" index 02d07576..4199b365 100644 Binary files "a/xyz.hotchpotch.hogandiff/messages.properties\347\256\241\347\220\206.xlsx" and "b/xyz.hotchpotch.hogandiff/messages.properties\347\256\241\347\220\206.xlsx" differ diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/AppResource.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/AppResource.java index ab6ab5fd..e44a1a5c 100644 --- a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/AppResource.java +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/AppResource.java @@ -53,7 +53,7 @@ public class AppResource { } /** プロパティファイルの相対パス */ - private static Path APP_PROP_PATH = USER_HOME != null + public static Path APP_PROP_PATH = USER_HOME != null ? USER_HOME.resolve("hogandiff.properties") : null; diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/SettingKeys.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/SettingKeys.java index facb230d..ec97fbb1 100644 --- a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/SettingKeys.java +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/SettingKeys.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.lang.reflect.Modifier; import java.nio.file.Path; +import java.time.Instant; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -316,6 +317,30 @@ private static Function decodeNotSupported(String msg) { Boolean::valueOf, true); + /** 起動時に新規バージョンの有無を確認するか */ + public static final Key CHECK_UPDATES = new Key<>( + "application.checkUpdates", + () -> false, + String::valueOf, + Boolean::valueOf, + true); + + /** 新バージョン有無の最終チェック日時 */ + public static final Key LAST_CHECK_UPDATES = new Key<>( + "application.lastCheckUpdates", + () -> null, + Instant::toString, + Instant::parse, + true); + + /** 新バージョン有無チェックの最短間隔(時間) */ + public static final Key CHECK_UPDATES_INTERVAL_HOURS = new Key<>( + "application.checkUpdatesIntervalHours", + () -> 6, + String::valueOf, + Integer::valueOf, + false); + /** 全ての定義済み設定項目を含むセット */ // Collectors#toSet は現在の実装では immutable set を返すが // 保証されないということなので、一応 Set#copyOf でラップしておく。 diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/MainController.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/MainController.java index ea8b0912..d03c2262 100644 --- a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/MainController.java +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/MainController.java @@ -143,6 +143,9 @@ public void initialize() { // 4.値変更時のイベントハンドラの設定 // nop + + // 5.その他 + UpdateChecker.execute(false); } /** diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/UpdateChecker.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/UpdateChecker.java new file mode 100644 index 00000000..1884f288 --- /dev/null +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/UpdateChecker.java @@ -0,0 +1,123 @@ +package xyz.hotchpotch.hogandiff.gui; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ResourceBundle; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; +import xyz.hotchpotch.hogandiff.AppMain; +import xyz.hotchpotch.hogandiff.AppResource; +import xyz.hotchpotch.hogandiff.SettingKeys; +import xyz.hotchpotch.hogandiff.util.NetUtil; + +/** + * このアプリケーションの更新チェック機能を提供します。
+ * + * @author nmby + */ +public class UpdateChecker { + + // [static members] ******************************************************** + + private static final AppResource ar = AppMain.appResource; + private static final ResourceBundle rb = ar.get(); + + /** + * 更新チェックを実行します。
+ * {@code force} に {@code true} が指定されている場合は、強制的にチェックします。
+ * {@code force} に {@code false} が指定されている場合は、 + * ユーザーが更新チェックを無効にしている場合、過去数時間以内にチェックしている場合はスキップします。
+ * + * @param force 強制的にチェックする場合は {@code true} + */ + public static void execute(boolean force) { + UpdateChecker checker = new UpdateChecker(); + checker.checkUpdate(force); + } + + // [instance members] ****************************************************** + + private UpdateChecker() { + } + + private void checkUpdate(boolean force) { + if (!force) { + if (!ar.settings().get(SettingKeys.CHECK_UPDATES)) { + return; + } + + Instant lastCheckAt = ar.settings().get(SettingKeys.LAST_CHECK_UPDATES); + int interval = ar.settings().get(SettingKeys.CHECK_UPDATES_INTERVAL_HOURS); + if (lastCheckAt != null && Instant.now().isBefore(lastCheckAt.plus(interval, ChronoUnit.HOURS))) { + return; + } + } + + CompletableFuture + .supplyAsync(() -> NetUtil.getAsJson("https://nmby.github.io/hogandiff4/api/versions/latest")) + .thenAccept(json -> { + String latestVersion = json.getString("version"); + if (!amILatest(latestVersion)) { + Platform.runLater(() -> { + Hyperlink link = UIUtil.createHyperlink(AppMain.WEB_URL); + VBox content = new VBox(10); + content.getChildren().addAll( + new Label(rb.getString("gui.UpdateChecker.020") + .formatted(AppMain.VERSION, latestVersion)), + link); + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle(rb.getString("AppMain.010")); + alert.setHeaderText(rb.getString("gui.UpdateChecker.010")); + alert.getDialogPane().setContent(content); + alert.showAndWait(); + }); + } else if (force) { + Platform.runLater(() -> { + new Alert( + AlertType.INFORMATION, + rb.getString("gui.UpdateChecker.030").formatted(AppMain.VERSION), + ButtonType.OK) + .showAndWait(); + }); + } + ar.changeSetting(SettingKeys.LAST_CHECK_UPDATES, Instant.now()); + }) + .exceptionally(throwable -> { + throwable.printStackTrace(); + return null; + }); + } + + private boolean amILatest(String latestVersion) { + Function toVersionNumbers = (v) -> { + String[] parts = v.replace("v", "").split("\\."); + if (parts.length != 3) { + throw new IllegalArgumentException("Invalid version string: " + v); + } + int[] numbers = new int[parts.length]; + for (int i = 0; i < parts.length; i++) { + numbers[i] = Integer.parseInt(parts[i]); + } + return numbers; + }; + + int[] latest = toVersionNumbers.apply(latestVersion); + int[] current = toVersionNumbers.apply(AppMain.VERSION); + for (int i = 0; i < latest.length; i++) { + if (latest[i] > current[i]) { + return false; + } else if (latest[i] < current[i]) { + return true; + } + } + return true; + } +} diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/GooglePane.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/GooglePane.java index bb8c9960..7ae81b52 100644 --- a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/GooglePane.java +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/GooglePane.java @@ -158,12 +158,14 @@ public void init(MainController parent, Object... param) { }); // 3.初期値の設定 - new Thread(() -> { + Thread asyncInitGoogleTask = new Thread(() -> { GoogleCredential credential = GoogleCredential.get(false); Platform.runLater(() -> { parent.googleCredential.setValue(credential); }); - }).start(); + }); + asyncInitGoogleTask.setDaemon(true); + asyncInitGoogleTask.start(); // 4.値変更時のイベントハンドラの設定 // nop diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.java index 32ec0209..ec87b5ba 100644 --- a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.java +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.java @@ -5,35 +5,28 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Locale; import java.util.Objects; import java.util.Optional; import java.util.ResourceBundle; import java.util.stream.Stream; -import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; -import javafx.geometry.Pos; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; -import javafx.scene.control.ComboBox; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; +import javafx.scene.control.Dialog; import javafx.scene.layout.VBox; import javafx.stage.DirectoryChooser; -import javafx.util.Callback; import xyz.hotchpotch.hogandiff.AppMain; import xyz.hotchpotch.hogandiff.AppResource; import xyz.hotchpotch.hogandiff.SettingKeys; import xyz.hotchpotch.hogandiff.gui.ChildController; import xyz.hotchpotch.hogandiff.gui.MainController; +import xyz.hotchpotch.hogandiff.gui.dialogs.SettingDetailsDialogPane; import xyz.hotchpotch.hogandiff.util.function.UnsafeConsumer; /** @@ -45,41 +38,6 @@ public class SettingsPane2 extends VBox implements ChildController { // [static members] ******************************************************** - private static enum LocaleItem { - - // [static members] ---------------------------------------------------- - - /** 日本語 */ - JA("日本語", Locale.JAPANESE, "jp.png"), - - /** 英語 */ - EN("English", Locale.ENGLISH, "us.png"), - - /** 中国語(簡体字) */ - ZH("簡体中文", Locale.SIMPLIFIED_CHINESE, "cn.png"); - - public static LocaleItem of(Locale locale) { - Objects.requireNonNull(locale); - - return Stream.of(values()) - .filter(item -> item.locale == locale) - .findFirst() - .orElseThrow(); - } - - // [instance members] -------------------------------------------------- - - private final String text; - private final Locale locale; - private final Image image; - - LocaleItem(String text, Locale locale, String imageSrc) { - this.text = text; - this.locale = locale; - this.image = new Image(imageSrc); - } - } - // [instance members] ****************************************************** private final AppResource ar = AppMain.appResource; @@ -88,9 +46,6 @@ public static LocaleItem of(Locale locale) { @FXML private GooglePane googlePane; - @FXML - private ComboBox localeComboBox; - @FXML private Button openWorkDirButton; @@ -100,6 +55,9 @@ public static LocaleItem of(Locale locale) { @FXML private Button deleteWorkDirButton; + @FXML + private Button detailsButton; + /** * コンストラクタ
* @@ -121,30 +79,29 @@ public void init(MainController parent, Object... param) { // 2.項目ごとの各種設定 googlePane.init(parent); - localeComboBox.setItems(FXCollections.observableArrayList(LocaleItem.values())); - localeComboBox.setButtonCell(cellFactory(false).call(null)); - localeComboBox.setCellFactory(cellFactory(true)); openWorkDirButton.setOnAction(openDir); changeWorkDirButton.setOnAction(changeDir); deleteWorkDirButton.setOnAction(deleteDir); - localeComboBox.setOnAction(event -> { - if (ar.changeSetting(SettingKeys.APP_LOCALE, localeComboBox.getValue().locale)) { - new Alert( - AlertType.INFORMATION, - "%s%n%n%s%n%n%s".formatted( - rb.getString("gui.component.SettingsPane2.051"), - rb.getString("gui.component.SettingsPane2.052"), - rb.getString("gui.component.SettingsPane2.053")), - ButtonType.OK) - .showAndWait(); + detailsButton.setOnAction(event -> { + try { + SettingDetailsDialogPane detailsContent = new SettingDetailsDialogPane(); + detailsContent.init(); + Dialog detailsDialog = new Dialog<>(); + detailsDialog.setTitle(rb.getString("gui.component.SettingsPane2.060")); + detailsDialog.getDialogPane().setContent(detailsContent); + detailsDialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE); + detailsDialog.showAndWait(); + + } catch (IOException e) { + e.printStackTrace(); + // nop } }); // 3.初期値の設定 - Locale locale = ar.settings().get(SettingKeys.APP_LOCALE); - localeComboBox.setValue(LocaleItem.of(locale)); + // nop // 4.値変更時のイベントハンドラの設定 // nop @@ -248,29 +205,4 @@ public void init(MainController parent, Object... param) { }); } }; - - private Callback, ListCell> cellFactory(boolean showText) { - return listView -> new ListCell<>() { - @Override - public void updateItem(LocaleItem item, boolean empty) { - super.updateItem(item, empty); - - if (empty || item == null) { - setText(null); - setGraphic(null); - } else { - ImageView iv = new ImageView(item.image); - iv.setFitHeight(17); - iv.setPreserveRatio(true); - setGraphic(iv); - - if (showText) { - setText(item.text); - } else { - this.setAlignment(Pos.CENTER); - } - } - } - }; - } } \ No newline at end of file diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/dialogs/SettingDetailsDialogPane.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/dialogs/SettingDetailsDialogPane.java new file mode 100644 index 00000000..b753d305 --- /dev/null +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/gui/dialogs/SettingDetailsDialogPane.java @@ -0,0 +1,206 @@ +package xyz.hotchpotch.hogandiff.gui.dialogs; + +import java.awt.Desktop; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Locale; +import java.util.Objects; +import java.util.Optional; +import java.util.ResourceBundle; +import java.util.stream.Stream; + +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.VBox; +import javafx.util.Callback; +import xyz.hotchpotch.hogandiff.AppMain; +import xyz.hotchpotch.hogandiff.AppResource; +import xyz.hotchpotch.hogandiff.SettingKeys; +import xyz.hotchpotch.hogandiff.gui.UpdateChecker; +import xyz.hotchpotch.hogandiff.logic.google.GoogleCredential; + +/** + * 詳細設定ダイアログの内容部分を提供します。
+ * + * @author nmby + */ +public class SettingDetailsDialogPane extends VBox { + + // [static members] ******************************************************** + + private static final AppResource ar = AppMain.appResource; + private static final ResourceBundle rb = ar.get(); + + private static enum LocaleItem { + + // [static members] ---------------------------------------------------- + + /** 日本語 */ + JA("日本語", Locale.JAPANESE, "jp.png"), + + /** 英語 */ + EN("English", Locale.ENGLISH, "us.png"), + + /** 中国語(簡体字) */ + ZH("簡体中文", Locale.SIMPLIFIED_CHINESE, "cn.png"); + + public static LocaleItem of(Locale locale) { + Objects.requireNonNull(locale); + + return Stream.of(values()) + .filter(item -> item.locale == locale) + .findFirst() + .orElseThrow(); + } + + // [instance members] -------------------------------------------------- + + private final String text; + private final Locale locale; + private final Image image; + + LocaleItem(String text, Locale locale, String imageSrc) { + this.text = text; + this.locale = locale; + this.image = new Image(imageSrc); + } + } + + // [instance members] ****************************************************** + + @FXML + private ComboBox localeComboBox; + + @FXML + private CheckBox checkUpdatesCheckBox; + + @FXML + private Button checkUpdatesImmediatelyButton; + + @FXML + private Button openSettingsFileButton; + + @FXML + private Button resetSettingsButton; + + /** + * コンストラクタ
+ * + * @throws IOException FXMLファイルの読み込みに失敗した場合 + */ + public SettingDetailsDialogPane() throws IOException { + FXMLLoader loader = new FXMLLoader(getClass().getResource("SettingDetailsDialogPane.fxml"), rb); + loader.setRoot(this); + loader.setController(this); + loader.load(); + } + + /** + * このオブジェクトを初期化します。
+ */ + public void init() { + // 1.disableプロパティのバインディング + // nop + + // 2.項目ごとの各種設定 + localeComboBox.setItems(FXCollections.observableArrayList(LocaleItem.values())); + localeComboBox.setButtonCell(cellFactory(false).call(null)); + localeComboBox.setCellFactory(cellFactory(true)); + + localeComboBox.setOnAction(event -> { + if (ar.changeSetting(SettingKeys.APP_LOCALE, localeComboBox.getValue().locale)) { + new Alert( + AlertType.INFORMATION, + "%s%n%n%s%n%n%s".formatted( + rb.getString("gui.component.SettingsPane2.051"), + rb.getString("gui.component.SettingsPane2.052"), + rb.getString("gui.component.SettingsPane2.053")), + ButtonType.OK) + .showAndWait(); + } + }); + + checkUpdatesImmediatelyButton.setOnAction(event -> { + UpdateChecker.execute(true); + }); + + openSettingsFileButton.setOnAction(event -> { + try { + Desktop.getDesktop().open(AppResource.APP_PROP_PATH.toFile()); + } catch (IOException e) { + e.printStackTrace(); + // nop + } + }); + + resetSettingsButton.setOnAction(event -> { + Optional result = new Alert( + AlertType.CONFIRMATION, + rb.getString("gui.dialogs.SettingDetailsDialogPane.010")) + .showAndWait(); + + if (result.isPresent() && result.get() == ButtonType.OK) { + try { + Files.deleteIfExists(AppResource.APP_PROP_PATH); + GoogleCredential credential = GoogleCredential.get(false); + if (credential != null) { + credential.deleteCredential(); + } + Platform.exit(); + } catch (Exception e) { + e.printStackTrace(); + // nop + } + } + }); + + // 3.初期値の設定 + Locale locale = ar.settings().get(SettingKeys.APP_LOCALE); + localeComboBox.setValue(LocaleItem.of(locale)); + + checkUpdatesCheckBox.setSelected(ar.settings().get(SettingKeys.CHECK_UPDATES)); + + // 4.値変更時のイベントハンドラの設定 + checkUpdatesCheckBox.setOnAction(event -> ar.changeSetting( + SettingKeys.CHECK_UPDATES, + checkUpdatesCheckBox.isSelected())); + } + + private Callback, ListCell> cellFactory(boolean showText) { + return listView -> new ListCell<>() { + @Override + public void updateItem(LocaleItem item, boolean empty) { + super.updateItem(item, empty); + + if (empty || item == null) { + setText(null); + setGraphic(null); + } else { + ImageView iv = new ImageView(item.image); + iv.setFitHeight(17); + iv.setPreserveRatio(true); + setGraphic(iv); + + if (showText) { + setText(item.text); + } else { + this.setAlignment(Pos.CENTER); + } + } + } + }; + } +} diff --git a/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/util/NetUtil.java b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/util/NetUtil.java new file mode 100644 index 00000000..d172258b --- /dev/null +++ b/xyz.hotchpotch.hogandiff/src/main/java/xyz/hotchpotch/hogandiff/util/NetUtil.java @@ -0,0 +1,52 @@ +package xyz.hotchpotch.hogandiff.util; + +import java.util.Objects; + +import org.json.JSONObject; + +import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpRequestFactory; +import com.google.api.client.http.HttpResponse; +import com.google.api.client.http.javanet.NetHttpTransport; + +/** + * ネットワーク関連のユーティリティクラスです。
+ * + * @author nmby + */ +public class NetUtil { + + // [static members] ******************************************************** + + private static final HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory(); + + /** + * 指定されたURLにGETリクエストを送り、レスポンスボディをJSONオブジェクトとして返します。
+ * + * @param url URL + * @return JSONオブジェクト + * @throws NullPointerException 引数に {@code null} が指定された場合 + */ + public static JSONObject getAsJson(String url) { + Objects.requireNonNull(url); + + try { + HttpRequest request = requestFactory.buildGetRequest(new GenericUrl(url)); + request.setConnectTimeout(5000); + request.setReadTimeout(5000); + + HttpResponse response = request.execute(); + String jsonString = response.parseAsString(); + return new JSONObject(jsonString); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // [instance members] ****************************************************** + + private NetUtil() { + } +} diff --git a/xyz.hotchpotch.hogandiff/src/main/resources/messages.properties b/xyz.hotchpotch.hogandiff/src/main/resources/messages.properties index d0534e93..ed6ded2b 100644 --- a/xyz.hotchpotch.hogandiff/src/main/resources/messages.properties +++ b/xyz.hotchpotch.hogandiff/src/main/resources/messages.properties @@ -23,6 +23,7 @@ fx.SettingsPane1.execute.040=精度優先 fx.SettingsPane2.010=言語 fx.SettingsPane2.020=作業用\nフォルダ fx.SettingsPane2.030=統計情報の収集に協力する +fx.SettingsPane2.040=詳細設定… fx.SettingsPane2.workDir.010=開く fx.SettingsPane2.workDir.020=変更... fx.SettingsPane2.workDir.030=削除... @@ -42,6 +43,12 @@ fx.GoogleFilePickerDialogPane.100=最近使ったファイル fx.GooglePane.010=Googleドライブ\n連携 fx.GooglePane.020=Googleドライブ\n連携解除 fx.GoogleRevisionSelectorDialog.010=Googleドライブからのファイルダウンロードに失敗しました。 +fx.SettingDetailsDialogPane.010=更新確認 +fx.SettingDetailsDialogPane.020=起動時に新規バージョンの有無を確認する +fx.SettingDetailsDialogPane.030=新規バージョンの有無を今すぐ確認する +fx.SettingDetailsDialogPane.040=設定 +fx.SettingDetailsDialogPane.050=設定ファイルを表示する +fx.SettingDetailsDialogPane.060=設定をリセットする… excel.poi.usermodel.TreeResultBookCreator.010=比較フォルダ%s: excel.poi.usermodel.TreeResultBookCreator.020=作業用フォルダ: @@ -65,6 +72,9 @@ gui.MainController.060=作業用フォルダの変更 gui.MainController.070=処理を中止しました。 gui.PasswordDialog.010=パスワード指定 gui.PasswordDialogPane.010=%s はパスワードで保護されています。 +gui.UpdateChecker.010=新しいバージョンが利用可能です。 +gui.UpdateChecker.020=新しいバージョンが利用可能です。\n\n - 現在のバージョン : %s\n - 最新バージョン : %s\n\n最新バージョンをダウンロードするには、Webサイトをご確認ください。 +gui.UpdateChecker.030=お使いのアプリケーションは最新バージョンです。\n - 現在のバージョン : %s gui.component.LinkPane.010=Webページの表示に失敗しました。ご利用のブラウザでお試しください。 gui.component.MenuPane.010=現在のバージョンでは未対応です。\n将来のバージョンにご期待ください! @@ -75,6 +85,7 @@ gui.component.SettingsPane2.040=次のフォルダの内容物を全て削除し gui.component.SettingsPane2.051=表示言語の変更を保存しました。\nアプリケーションを再起動すると変更が反映されます。 gui.component.SettingsPane2.052=Display language change is saved. \nRestart the application to reflect the change. gui.component.SettingsPane2.053=对显示语言的改变已经被保存。\n重新启动应用程序,这些变化就会生效。 +gui.component.SettingsPane2.060=方眼Diff - 詳細設定 gui.component.TargetSelectionPane.010=比較対象フォルダの選択 gui.component.TargetSelectionPane.020=比較対象ブックの選択 gui.component.TargetSelectionPane.030=Excel ブック @@ -94,6 +105,8 @@ gui.component.GooglePane.090=Googleドライブからファイルをダウンロ gui.component.GooglePane.100=選択されたファイルをGoogleドライブからダウンロードしてこのPCの下記リンク先フォルダに保存しました。\nPC上に保存された状態が好ましくない場合は、比較処理が終わり次第、ご自身で削除してください。 gui.component.GooglePane.110=次回以降、このメッセージを表示しない +gui.dialogs.SettingDetailsDialogPane.010=設定を初期化しアプリケーションを終了します。\nよろしいですか? + AppMain.010=方眼Diff AppResource.010=設定の保存に失敗しました。 diff --git a/xyz.hotchpotch.hogandiff/src/main/resources/messages_en.properties b/xyz.hotchpotch.hogandiff/src/main/resources/messages_en.properties index 8f3b5ac6..b8e77bbe 100644 --- a/xyz.hotchpotch.hogandiff/src/main/resources/messages_en.properties +++ b/xyz.hotchpotch.hogandiff/src/main/resources/messages_en.properties @@ -23,6 +23,7 @@ fx.SettingsPane1.execute.040=Prioritize accuracy fx.SettingsPane2.010=Language fx.SettingsPane2.020=Working directory fx.SettingsPane2.030=Allow usage data collection +fx.SettingsPane2.040=Advanced Settings… fx.SettingsPane2.workDir.010=Open fx.SettingsPane2.workDir.020=Change... fx.SettingsPane2.workDir.030=Delete... @@ -42,6 +43,12 @@ fx.GoogleFilePickerDialogPane.100=Recently picked fx.GooglePane.010=Connect\nGoogle Drive fx.GooglePane.020=Disconnect\nGoogle Drive fx.GoogleRevisionSelectorDialog.010=Failed to download the file from Google Drive. +fx.SettingDetailsDialogPane.010=Update Check +fx.SettingDetailsDialogPane.020=Check for new versions at startup +fx.SettingDetailsDialogPane.030=Check for new versions now +fx.SettingDetailsDialogPane.040=Settings +fx.SettingDetailsDialogPane.050=Display the configuration file +fx.SettingDetailsDialogPane.060=Reset settings… excel.poi.usermodel.TreeResultBookCreator.010=Folder %s : excel.poi.usermodel.TreeResultBookCreator.020=Working dir : @@ -65,6 +72,9 @@ gui.MainController.060=Change working directory gui.MainController.070=Processing has been canceled. gui.PasswordDialog.010=Enter Password gui.PasswordDialogPane.010=The book [%s] is password protected. +gui.UpdateChecker.010=A new version is available. +gui.UpdateChecker.020=A new version is available.\n\n - Current version : %s\n - Latest version : %s\n\nTo download the latest version, please visit: +gui.UpdateChecker.030=Your application is up to date.\n - Current version : %s gui.component.LinkPane.010=Failed to open the website. Please try using your browser. gui.component.MenuPane.010=This is not supported in the current version.\nStay tuned for future versions! @@ -75,6 +85,7 @@ gui.component.SettingsPane2.040=Delete all contents of the following directory. gui.component.SettingsPane2.051=表示言語の変更を保存しました。\nアプリケーションを再起動すると変更が反映されます。 gui.component.SettingsPane2.052=Display language change is saved. \nRestart the application to reflect the change. gui.component.SettingsPane2.053=对显示语言的改变已经被保存。\n重新启动应用程序,这些变化就会生效。 +gui.component.SettingsPane2.060=HoganDiff - Advanced Settings gui.component.TargetSelectionPane.010=Select comparison folder gui.component.TargetSelectionPane.020=Select comparison book gui.component.TargetSelectionPane.030=Excel book @@ -94,6 +105,8 @@ gui.component.GooglePane.090=File downloaded from Google Drive gui.component.GooglePane.100=The selected file has been downloaded from Google Drive and saved to the folder linked below on this PC.\nIf you prefer not to keep the file stored on your PC, please delete it manually after the comparison process is complete. gui.component.GooglePane.110=Don't show this message again +gui.dialogs.SettingDetailsDialogPane.010=Initialize settings and exit the application.\nAre you sure? + AppMain.010=HoganDiff (方眼Diff) AppResource.010=Failed to save settings. diff --git a/xyz.hotchpotch.hogandiff/src/main/resources/messages_zh.properties b/xyz.hotchpotch.hogandiff/src/main/resources/messages_zh.properties index 086be4d9..45558d1d 100644 --- a/xyz.hotchpotch.hogandiff/src/main/resources/messages_zh.properties +++ b/xyz.hotchpotch.hogandiff/src/main/resources/messages_zh.properties @@ -23,6 +23,7 @@ fx.SettingsPane1.execute.040=优先考虑准确性 fx.SettingsPane2.010=语言 fx.SettingsPane2.020=工作\n文件夹 fx.SettingsPane2.030=同意收集使用统计信息 +fx.SettingsPane2.040=详细设置... fx.SettingsPane2.workDir.010=打开 fx.SettingsPane2.workDir.020=改变... fx.SettingsPane2.workDir.030=删除... @@ -42,6 +43,12 @@ fx.GoogleFilePickerDialogPane.100=最近使用的文件 fx.GooglePane.010=Google Drive\n关联 fx.GooglePane.020=Google Drive\n关联解除 fx.GoogleRevisionSelectorDialog.010=从Google云端硬盘下载文件失败。 +fx.SettingDetailsDialogPane.010=更新确认 +fx.SettingDetailsDialogPane.020=启动时检查是否有新版本 +fx.SettingDetailsDialogPane.030=立即检查是否有新版本 +fx.SettingDetailsDialogPane.040=设置 +fx.SettingDetailsDialogPane.050=显示配置文件 +fx.SettingDetailsDialogPane.060=重置设置… excel.poi.usermodel.TreeResultBookCreator.010=文件夹%s: excel.poi.usermodel.TreeResultBookCreator.020=工作文件夹: @@ -65,6 +72,9 @@ gui.MainController.060=改变工作文件夹 gui.MainController.070=处理已被取消。 gui.PasswordDialog.010=输入密码 gui.PasswordDialogPane.010=%s 是受密码保护的。 +gui.UpdateChecker.010=有新版本可用。 +gui.UpdateChecker.020=有新版本可用。\n\n - 当前版本 : %s\n - 最新版本 : %s\n\n要下载最新版本,请访问: +gui.UpdateChecker.030=您的应用程序已是最新版本。\n - 当前版本 : %s gui.component.LinkPane.010=网页未能显示。 请尝试使用你的浏览器。 gui.component.MenuPane.010=当前版本不支持此功能。\n请继续关注未来版本! @@ -75,6 +85,7 @@ gui.component.SettingsPane2.040=删除以下文件夹的所有内容。你确定 gui.component.SettingsPane2.051=表示言語の変更を保存しました。\nアプリケーションを再起動すると変更が反映されます。 gui.component.SettingsPane2.052=Display language change is saved. \nRestart the application to reflect the change. gui.component.SettingsPane2.053=对显示语言的改变已经被保存。\n重新启动应用程序,这些变化就会生效。 +gui.component.SettingsPane2.060=方眼Diff - 详细设置 gui.component.TargetSelectionPane.010=选择用于比较的文件夹 gui.component.TargetSelectionPane.020=选择用于比较的工作簿 gui.component.TargetSelectionPane.030=Excel工作簿 @@ -94,6 +105,8 @@ gui.component.GooglePane.090=已从Google云端硬盘下载文件 gui.component.GooglePane.100=已从Google云端硬盘下载所选文件,并保存到本机下方链接的文件夹中。\n如果您不希望文件保存在电脑上,请在比较处理完成后自行删除。 gui.component.GooglePane.110=不再显示此消息 +gui.dialogs.SettingDetailsDialogPane.010=初始化设置并退出应用程序。\n确定吗? + AppMain.010=方眼Diff AppResource.010=保存设置失败。 diff --git a/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/application.css b/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/application.css index 910c0b5a..ed09fd11 100644 --- a/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/application.css +++ b/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/application.css @@ -87,6 +87,17 @@ -fx-pref-width: 65.0px; } +.detailsPane { + -fx-background-color: rgb(230.0, 240.0, 255.0); + -fx-spacing: 3.0px; +} + +.detailsTitleLabel { + -fx-background-color: rgb(196.0, 219.0, 255.0); + -fx-padding: 0.0px 7.0px 0.0px 5.0px; + -fx-pref-width: 99.0px; +} + .localeComboBox { -fx-pref-width: 70.0px; } diff --git a/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.fxml b/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.fxml index f3c231d2..7ca613c3 100644 --- a/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.fxml +++ b/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/components/SettingsPane2.fxml @@ -2,115 +2,55 @@ - - + - - + + - - + + - + + + - - - - - - - - - - - - - - - - - + + + + diff --git a/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/dialogs/SettingDetailsDialogPane.fxml b/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/dialogs/SettingDetailsDialogPane.fxml new file mode 100644 index 00000000..32e96e3c --- /dev/null +++ b/xyz.hotchpotch.hogandiff/src/main/resources/xyz/hotchpotch/hogandiff/gui/dialogs/SettingDetailsDialogPane.fxml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xyz.hotchpotch.hogandiff/src/test/java/xyz/hotchpotch/hogandiff/logic/poi/PoiUtilTest1_possibleTypes.java b/xyz.hotchpotch.hogandiff/src/test/java/xyz/hotchpotch/hogandiff/logic/poi/PoiUtilTest1_possibleTypes.java index ec024371..22a4dddf 100644 --- a/xyz.hotchpotch.hogandiff/src/test/java/xyz/hotchpotch/hogandiff/logic/poi/PoiUtilTest1_possibleTypes.java +++ b/xyz.hotchpotch.hogandiff/src/test/java/xyz/hotchpotch/hogandiff/logic/poi/PoiUtilTest1_possibleTypes.java @@ -97,8 +97,7 @@ static void afterAll() throws IOException { EnumSet.of(SheetType.CHART_SHEET), PoiUtil.possibleTypes(test1_xlsm_A2_ChartSheet)); - // FIXME: [No.01 シート識別不正 - usermodel] どういう訳か .xlsm - // 形式のExcelブックから「3_ダイアログ」を読み込めない。 + // FIXME: [No.01 シート識別不正 - usermodel] どういう訳か .xlsm 形式のExcelブックから「3_ダイアログ」を読み込めない。 // つまり test1_xlsm_A3_DialogSheet == null。なのでテストできない。 // どうしようもないのかしら?? // assertEquals(