Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,36 @@
import javafx.beans.property.StringProperty;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Skin;

import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jetbrains.annotations.NotNull;

public class ProfileListItem extends RadioButton {
private final Profile profile;
private final StringProperty title = new SimpleStringProperty();
private final StringProperty subtitle = new SimpleStringProperty();

public ProfileListItem(Profile profile) {
public ProfileListItem(@NotNull Profile profile) {
this.profile = profile;
getStyleClass().setAll("profile-list-item", "navigation-drawer-item");
setUserData(profile);

title.set(Profiles.getProfileDisplayName(profile));
subtitle.set(profile.getGameDir().toString());

profile.nameProperty().addListener((obs, oldVal, newVal) -> title.set(Profiles.getProfileDisplayName(profile)));
profile.gameDirProperty().addListener((obs, oldVal, newVal) -> subtitle.set(profile.getGameDir().toString()));

FXUtils.onSecondaryButtonClicked(this, () -> ProfileListPopupMenu.show(this, profile));
}

@Override
protected Skin<?> createDefaultSkin() {
return new ProfileListItemSkin(this);
}

/// Removes this profile from the list.
public void remove() {
Profiles.getProfiles().remove(profile);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.profile;

import com.jfoenix.controls.JFXPopup;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.construct.IconedMenuItem;
import org.jackhuang.hmcl.ui.construct.PopupMenu;

import static org.jackhuang.hmcl.util.i18n.I18n.i18n;

/// Popup menu for ProfileListItem.
public final class ProfileListPopupMenu extends StackPane {

/// Shows the popup menu for the given profile item.
public static void show(Node owner, Profile profile) {
PopupMenu menu = new PopupMenu();
JFXPopup popup = new JFXPopup(menu);
menu.getContent().add(new IconedMenuItem(
org.jackhuang.hmcl.ui.SVG.EDIT,
i18n("button.edit"),
() -> Controllers.navigate(new ProfilePage(profile)),
popup));
popup.show(owner, JFXPopup.PopupVPosition.BOTTOM, JFXPopup.PopupHPosition.LEFT, 0, 0);
}

public ProfileListPopupMenu() {
getStyleClass().add("popup-menu-content");
}
}
16 changes: 12 additions & 4 deletions HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfilePage.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public final class ProfilePage extends BorderPane implements DecoratorPage {
private final JFXTextField txtProfileName;
private final LineFileChooserButton gameDir;
private final LineToggleButton toggleUseRelativePath;
private ChangeListener<String> locationChangeListener;
private ChangeListener<String> txtProfileNameChangeListener;

/**
* @param profile null if creating a new profile.
Expand Down Expand Up @@ -99,7 +101,9 @@ public ProfilePage(Profile profile) {
@Override
protected void eval() {
JFXTextField control = (JFXTextField) this.getSrcControl();
hasErrors.set(Profiles.getProfiles().stream().anyMatch(profile -> profile.getName().equals(control.getText())));
hasErrors.set(Profiles.getProfiles().stream()
.filter(p -> p != profile)
.anyMatch(p -> p.getName().equals(control.getText())));
}
});
}
Expand Down Expand Up @@ -144,7 +148,7 @@ protected void eval() {
txtProfileName.textProperty(), location));
}

ChangeListener<String> locationChangeListener = (observable, oldValue, newValue) -> {
locationChangeListener = (observable, oldValue, newValue) -> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本审查建议由 GPT-5 生成


locationChangeListener 仍然在编辑模式注册。右键编辑现有实例后,如果用户先把实例目录改到某个 .../.minecraft 路径,监听器会把名称输入框自动改成父目录名,保存时就会静默重命名实例。这和 PR 描述里的“路径变化后不再自动修改名称”不一致。建议只在 profile == null 的新建流程中启用这个自动命名监听器,或进入编辑模式时直接禁用它。

Path newPath;
try {
newPath = FileUtils.toAbsolute(Path.of(newValue));
Expand All @@ -166,18 +170,22 @@ protected void eval() {
};
locationProperty().addListener(locationChangeListener);

txtProfileName.textProperty().addListener(new ChangeListener<>() {
txtProfileNameChangeListener = new ChangeListener<>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (txtProfileName.isFocused()) {
txtProfileName.textProperty().removeListener(this);
locationProperty().removeListener(locationChangeListener);
}
}
});
};
txtProfileName.textProperty().addListener(txtProfileNameChangeListener);
}

private void onSave() {
locationProperty().removeListener(locationChangeListener);
txtProfileName.textProperty().removeListener(txtProfileNameChangeListener);

if (profile != null) {
profile.setName(txtProfileName.getText());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本审查建议由 GPT-5 生成


编辑现有实例时,名称输入框使用 Profiles.getProfileDisplayName(profile) 初始化,但保存时又把 txtProfileName.getText() 写回 profile.setName(...)。这会让 Default / Home 这类保留名称在非英文语言下被保存成翻译后的显示名。触发条件是右键编辑默认/主目录实例后直接保存,哪怕只改路径或相对路径开关。结果是配置 key 被改掉,内置实例失去保留名称身份。建议编辑框使用 profile.getName() 作为真实名称,显示名只用于列表/标题展示。

profile.setUseRelativePath(toggleUseRelativePath.isSelected());
Expand Down