rework translation dialogs

This commit is contained in:
marhali 2022-04-11 19:14:07 +02:00
parent fc1eb07443
commit c9ef651673
4 changed files with 204 additions and 169 deletions

View File

@ -6,10 +6,10 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.ui.content.Content; import com.intellij.ui.content.Content;
import de.marhali.easyi18n.model.KeyPath;
import de.marhali.easyi18n.model.KeyPathConverter;
import de.marhali.easyi18n.service.WindowManager;
import de.marhali.easyi18n.dialog.AddDialog; import de.marhali.easyi18n.dialog.AddDialog;
import de.marhali.easyi18n.model.translation.KeyPath;
import de.marhali.easyi18n.service.WindowManager;
import de.marhali.easyi18n.util.KeyPathConverter;
import de.marhali.easyi18n.util.TreeUtil; import de.marhali.easyi18n.util.TreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -32,7 +32,7 @@ public class AddAction extends AnAction {
@Override @Override
public void actionPerformed(@NotNull AnActionEvent e) { public void actionPerformed(@NotNull AnActionEvent e) {
new AddDialog(Objects.requireNonNull(e.getProject()), detectPreKey(e.getProject())).showAndHandle(); new AddDialog(Objects.requireNonNull(e.getProject()), detectPreKey(e.getProject()), null).showAndHandle();
} }
private @Nullable KeyPath detectPreKey(@NotNull Project project) { private @Nullable KeyPath detectPreKey(@NotNull Project project) {
@ -58,7 +58,7 @@ public class AddAction extends AnAction {
if(row >= 0) { if(row >= 0) {
String path = String.valueOf(window.getTableView().getTable().getValueAt(row, 0)); String path = String.valueOf(window.getTableView().getTable().getValueAt(row, 0));
return converter.split(path); return converter.fromString(path);
} }
} }

View File

@ -3,112 +3,64 @@ package de.marhali.easyi18n.dialog;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import de.marhali.easyi18n.InstanceManager; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.*; import de.marhali.easyi18n.model.TranslationCreate;
import de.marhali.easyi18n.model.translation.KeyPath;
import de.marhali.easyi18n.model.translation.Translation;
import de.marhali.easyi18n.model.translation.TranslationValue;
import de.marhali.easyi18n.settings.ProjectSettingsService;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/** /**
* Create translation dialog. * Dialog to create a new translation with all associated locale values.
* Supports optional prefill technique for translation key or locale value.
* @author marhali * @author marhali
*/ */
public class AddDialog { public class AddDialog extends TranslationDialog {
private final @NotNull Project project; /**
private final @NotNull KeyPathConverter converter; * Constructs a new create dialog with prefilled fields
* @param project Opened project
private @NotNull KeyPath preKey; * @param prefillKey Prefill translation key
* @param prefillLocale Prefill preview locale value
private JBTextField keyTextField; */
private Map<String, JBTextField> valueTextFields; public AddDialog(@NotNull Project project, @Nullable KeyPath prefillKey, @Nullable String prefillLocale) {
super(project, new Translation(prefillKey != null ? prefillKey : new KeyPath(),
public AddDialog(@NotNull Project project, @Nullable KeyPath preKey) { prefillLocale != null
this(project); ? new TranslationValue(ProjectSettingsService.get(project).getState().getPreviewLocale(), prefillLocale)
this.preKey = preKey == null ? new KeyPath() : preKey; : null)
);
} }
/**
* Constructs a new create dialog without prefilled fields.
* @param project Opened project
*/
public AddDialog(@NotNull Project project) { public AddDialog(@NotNull Project project) {
this.project = project; this(project, new KeyPath(), "");
this.converter = new KeyPathConverter(project);
this.preKey = new KeyPath();
} }
public void showAndHandle() {
int code = prepare().show();
if(code == DialogWrapper.OK_EXIT_CODE) {
saveTranslation();
}
}
private void saveTranslation() {
Translation translation = new Translation();
valueTextFields.forEach((k, v) -> {
if(!v.getText().isEmpty()) {
translation.put(k, v.getText());
}
});
KeyedTranslation keyedTranslation = new KeyedTranslation(converter.split(keyTextField.getText()), translation);
TranslationCreate creation = new TranslationCreate(keyedTranslation);
InstanceManager.get(project).processUpdate(creation);
}
private DialogBuilder prepare() {
JPanel rootPanel = new JPanel();
rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.PAGE_AXIS));
JPanel keyPanel = new JPanel(new GridLayout(0, 1, 2, 2));
JBLabel keyLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("translation.key"));
keyTextField = new JBTextField(this.converter.concat(this.preKey));
keyLabel.setLabelFor(keyTextField);
keyPanel.add(keyLabel);
keyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
keyPanel.add(keyTextField);
rootPanel.add(keyPanel);
if(!this.preKey.isEmpty()) { // Add delimiter if pre key is defined
keyTextField.setText(keyTextField.getText() + KeyPath.DELIMITER);
}
JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2));
valueTextFields = new HashMap<>();
for(String locale : InstanceManager.get(project).store().getData().getLocales()) {
JBLabel localeLabel = new JBLabel(locale);
JBTextField localeText = new JBTextField();
localeLabel.setLabelFor(localeText);
valuePanel.add(localeLabel);
valuePanel.add(localeText);
valueTextFields.put(locale, localeText);
}
JBScrollPane valuePane = new JBScrollPane(valuePanel);
valuePane.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(),
ResourceBundle.getBundle("messages").getString("translation.locales")));
rootPanel.add(valuePane);
@Override
protected @NotNull DialogBuilder configure(@NotNull JComponent centerPanel) {
DialogBuilder builder = new DialogBuilder(); DialogBuilder builder = new DialogBuilder();
builder.setTitle(ResourceBundle.getBundle("messages").getString("action.add")); builder.setTitle(bundle.getString("action.add"));
builder.removeAllActions(); builder.removeAllActions();
builder.addOkAction(); builder.addOkAction();
builder.addCancelAction(); builder.addCancelAction();
builder.setCenterPanel(rootPanel); builder.setCenterPanel(centerPanel);
return builder; return builder;
} }
@Override
protected void handleExit(int exitCode) {
if(exitCode == DialogWrapper.OK_EXIT_CODE) {
InstanceManager.get(project).processUpdate(new TranslationCreate(getState()));
}
}
} }

View File

@ -3,102 +3,53 @@ package de.marhali.easyi18n.dialog;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import de.marhali.easyi18n.InstanceManager; import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.*;
import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor; import de.marhali.easyi18n.dialog.descriptor.DeleteActionDescriptor;
import de.marhali.easyi18n.model.TranslationDelete;
import de.marhali.easyi18n.model.TranslationUpdate;
import de.marhali.easyi18n.model.translation.Translation;
import org.jetbrains.annotations.NotNull;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/** /**
* Edit translation dialog. * Dialog to edit or delete an existing translation.
* @author marhali * @author marhali
*/ */
public class EditDialog { public class EditDialog extends TranslationDialog {
private final Project project; /**
private final KeyPathConverter converter; * Constructs a new edit dialog with the provided translation
* @param project Opened project
private final KeyedTranslation origin; * @param origin Translation to edit
*/
private JBTextField keyTextField; public EditDialog(@NotNull Project project, @NotNull Translation origin) {
private Map<String, JBTextField> valueTextFields; super(project, origin);
public EditDialog(Project project, KeyedTranslation origin) {
this.project = project;
this.converter = new KeyPathConverter(project);
this.origin = origin;
} }
public void showAndHandle() { @Override
int code = prepare().show(); protected @NotNull DialogBuilder configure(@NotNull JComponent centerPanel) {
if(code == DialogWrapper.OK_EXIT_CODE) { // Edit
InstanceManager.get(project).processUpdate(new TranslationUpdate(origin, getChanges()));
} else if(code == DeleteActionDescriptor.EXIT_CODE) { // Delete
InstanceManager.get(project).processUpdate(new TranslationDelete(origin));
}
}
private KeyedTranslation getChanges() {
Translation translation = new Translation();
valueTextFields.forEach((k, v) -> {
if(!v.getText().isEmpty()) {
translation.put(k, v.getText());
}
});
return new KeyedTranslation(converter.split(keyTextField.getText()), translation);
}
private DialogBuilder prepare() {
JPanel rootPanel = new JPanel();
rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.PAGE_AXIS));
JPanel keyPanel = new JPanel(new GridLayout(0, 1, 2,2));
JBLabel keyLabel = new JBLabel(ResourceBundle.getBundle("messages").getString("translation.key"));
keyTextField = new JBTextField(this.converter.concat(this.origin.getKey()));
keyLabel.setLabelFor(keyTextField);
keyPanel.add(keyLabel);
keyPanel.add(keyTextField);
keyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
rootPanel.add(keyPanel);
JPanel valuePanel = new JPanel(new GridLayout(0, 1, 2, 2));
valueTextFields = new HashMap<>();
for(String locale : InstanceManager.get(project).store().getData().getLocales()) {
JBLabel localeLabel = new JBLabel(locale);
JBTextField localeText = new JBTextField(this.origin.getTranslation().get(locale));
localeLabel.setLabelFor(localeText);
valuePanel.add(localeLabel);
valuePanel.add(localeText);
valueTextFields.put(locale, localeText);
}
JBScrollPane valuePane = new JBScrollPane(valuePanel);
valuePane.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(),
ResourceBundle.getBundle("messages").getString("translation.locales")));
rootPanel.add(valuePane);
DialogBuilder builder = new DialogBuilder(); DialogBuilder builder = new DialogBuilder();
builder.setTitle(ResourceBundle.getBundle("messages").getString("action.edit")); builder.setTitle(bundle.getString("action.edit"));
builder.removeAllActions(); builder.removeAllActions();
builder.addCancelAction(); builder.addCancelAction();
builder.addActionDescriptor(new DeleteActionDescriptor()); builder.addActionDescriptor(new DeleteActionDescriptor());
builder.addOkAction(); builder.addOkAction();
builder.setCenterPanel(rootPanel); builder.setCenterPanel(centerPanel);
return builder; return builder;
} }
@Override
protected void handleExit(int exitCode) {
switch (exitCode) {
case DialogWrapper.OK_EXIT_CODE:
InstanceManager.get(project).processUpdate(new TranslationUpdate(origin, getState()));
break;
case DeleteActionDescriptor.EXIT_CODE:
InstanceManager.get(project).processUpdate(new TranslationDelete(origin));
break;
}
}
} }

View File

@ -0,0 +1,132 @@
package de.marhali.easyi18n.dialog;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.FormBuilder;
import de.marhali.easyi18n.InstanceManager;
import de.marhali.easyi18n.model.translation.KeyPath;
import de.marhali.easyi18n.model.translation.Translation;
import de.marhali.easyi18n.model.translation.TranslationValue;
import de.marhali.easyi18n.settings.ProjectSettings;
import de.marhali.easyi18n.settings.ProjectSettingsService;
import de.marhali.easyi18n.util.KeyPathConverter;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/**
* Base for add and edit translation dialogs.
* @author marhali
*/
abstract class TranslationDialog {
protected static final ResourceBundle bundle = ResourceBundle.getBundle("messages");
protected final @NotNull Project project;
protected final @NotNull ProjectSettings settings;
protected final @NotNull KeyPathConverter converter;
protected final @NotNull Translation origin;
protected final JTextField keyField;
protected final JTextField descriptionField;
protected final Map<String, JTextField> localeValueFields;
/**
* Constructs a new translation dialog.
* @param project Opened project
* @param origin Prefill translation
*/
protected TranslationDialog(@NotNull Project project, @NotNull Translation origin) {
this.project = project;
this.settings = ProjectSettingsService.get(project).getState();
this.converter = new KeyPathConverter(settings);
this.origin = origin;
// Fields
TranslationValue value = origin.getValue();
this.keyField = new JBTextField(converter.toString(origin.getKey()));
this.descriptionField = new JBTextField(value != null ? value.getDescription() : null);
this.localeValueFields = new HashMap<>();
for(String locale : InstanceManager.get(project).store().getData().getLocales()) {
localeValueFields.put(locale, new JBTextField(value != null ? value.get(locale) : null));
}
}
/**
* Implementation needs to configure the dialog. E.g. title, actions, ...
* The implementation needs to set the provided centerPanel as the view panel.
* @param centerPanel GUI to set on the dialog builder
* @return configured dialog builder
*/
protected abstract @NotNull DialogBuilder configure(@NotNull JComponent centerPanel);
/**
* Implementation needs to handle exit
* @param exitCode See {@link com.intellij.openapi.ui.DialogWrapper} for exit codes
*/
protected abstract void handleExit(int exitCode);
/**
* Opens the translation modal and applies the appropriate logic on modal close.
* Internally, the {@link #handleExit(int)} method will be called to determine finalization logic.
*/
public void showAndHandle() {
int exitCode = createDialog().show();
handleExit(exitCode);
}
/**
* Retrieve current modal state.
* @return Translation
*/
protected @NotNull Translation getState() {
KeyPath key = converter.fromString(keyField.getText());
TranslationValue value = new TranslationValue();
value.setDescription(descriptionField.getText());
for(Map.Entry<String, JTextField> entry : localeValueFields.entrySet()) {
value.put(entry.getKey(), entry.getValue().getText());
}
return new Translation(key, value);
}
private DialogBuilder createDialog() {
JPanel panel = FormBuilder.createFormBuilder()
.addLabeledComponent(bundle.getString("translation.key"), keyField, true)
.addLabeledComponent(bundle.getString("translation.description"), descriptionField, 6, true)
.addComponent(createLocalesPanel(), 12)
.getPanel();
panel.setMinimumSize(new Dimension(200, 150));
return configure(panel);
}
private JComponent createLocalesPanel() {
FormBuilder builder = FormBuilder.createFormBuilder();
for(Map.Entry<String, JTextField> localeEntry : localeValueFields.entrySet()) {
builder.addLabeledComponent(localeEntry.getKey(), localeEntry.getValue(), 6, true);
}
JScrollPane scrollPane = new JBScrollPane(builder.getPanel());
scrollPane.setBorder(BorderFactory.createTitledBorder(
new EtchedBorder(), bundle.getString("translation.locales")));
return scrollPane;
}
}