diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java index 0872816c4..25d4d990a 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java @@ -343,12 +343,14 @@ private void configureUI() { UIManager.put("Action.closeOthersIcon", new FlatSVGIcon("icons/actions/tab_close_others.svg")); UIManager.put("Action.closeUninitializedIcon", new FlatSVGIcon("icons/actions/tab_close_uninitialized.svg")); UIManager.put("Action.containsIcon", new FlatSVGIcon("icons/actions/contains.svg")); + UIManager.put("Action.copyIcon", new FlatSVGIcon("icons/actions/copy.svg")); UIManager.put("Action.duplicateElementIcon", new FlatSVGIcon("icons/actions/duplicate_element.svg")); UIManager.put("Action.editIcon", new FlatSVGIcon("icons/actions/edit.svg")); UIManager.put("Action.editModalIcon", new FlatSVGIcon("icons/actions/edit_modal.svg")); UIManager.put("Action.exportIcon", new FlatSVGIcon("icons/actions/export.svg")); UIManager.put("Action.hideIcon", new FlatSVGIcon("icons/actions/hide.svg")); UIManager.put("Action.importIcon", new FlatSVGIcon("icons/actions/import.svg")); + UIManager.put("Action.informationIcon", new FlatSVGIcon("icons/actions/information.svg")); UIManager.put("Action.navigateIcon", new FlatSVGIcon("icons/actions/navigate.svg")); UIManager.put("Action.nextIcon", new FlatSVGIcon("icons/actions/next.svg")); UIManager.put("Action.normalsIcon", new FlatSVGIcon("icons/actions/normals.svg")); diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/dialogs/ProjectEditDialog.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/dialogs/ProjectEditDialog.java index 6309ebce5..8c9b32828 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/dialogs/ProjectEditDialog.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/dialogs/ProjectEditDialog.java @@ -25,9 +25,10 @@ import java.util.Objects; public class ProjectEditDialog extends BaseEditDialog { - private final boolean edit; + private final boolean persisted; + private final boolean editable; - private final JTextField projectUuid; + private final JTextField projectId; private final JTextField projectName; private final JComboBox projectType; private final JTextField executableFilePath; @@ -37,22 +38,42 @@ public class ProjectEditDialog extends BaseEditDialog { private final JTextField rttiInfoFilePath; private final JTextField fileListingsPath; - public ProjectEditDialog(boolean edit) { - super(edit ? "Edit Project" : "New Project"); + public ProjectEditDialog(boolean persisted, boolean editable) { + super(persisted ? "Edit Project" : "New Project"); + this.persisted = persisted; + this.editable = editable; - this.edit = edit; + this.projectId = new JTextField(); + this.projectId.setEditable(false); - this.projectUuid = new JTextField(); - this.projectUuid.setEditable(false); this.projectName = new JTextField(); + this.projectName.setEnabled(editable); + this.projectType = new JComboBox<>(GameType.values()); + this.projectType.setEnabled(editable); + this.projectType.addItemListener(e -> fillValuesBasedOnGameType((GameType) e.getItem(), projectType.getItemAt(projectType.getSelectedIndex()))); + this.executableFilePath = new JTextField(); + this.executableFilePath.setEnabled(editable); + this.executableFilePath.getDocument().addDocumentListener((DocumentAdapter) e -> { + if (UIUtils.isValid(executableFilePath)) { + fillValuesBasedOnGameExecutable(Path.of(executableFilePath.getText())); + } + }); + this.archiveFolderPath = new JTextField(); + this.archiveFolderPath.setEnabled(editable); + this.compressorPath = new JTextField(); - this.compressorNote = new ColoredComponent(); + this.compressorPath.setEnabled(editable); + this.rttiInfoFilePath = new JTextField(); + this.rttiInfoFilePath.setEnabled(editable); + this.fileListingsPath = new JTextField(); + this.fileListingsPath.setEnabled(editable); + this.compressorNote = new ColoredComponent(); this.compressorNote.setVisible(false); this.compressorPath.getDocument().addDocumentListener((DocumentAdapter) e -> { if (UIUtils.isValid(compressorPath)) { @@ -72,7 +93,7 @@ public ProjectEditDialog(boolean edit) { fitContent(); }); - if (!edit) { + if (!persisted) { projectType.addItemListener(e -> fillValuesBasedOnGameType((GameType) e.getItem(), projectType.getItemAt(projectType.getSelectedIndex()))); executableFilePath.getDocument().addDocumentListener((DocumentAdapter) e -> { @@ -91,9 +112,11 @@ protected JComponent createContentsPane() { panel.add(new LabeledSeparator("Project"), "span,wrap"); - if (edit) { + if (persisted) { panel.add(new JLabel("UUID:"), "gap ind"); - panel.add(projectUuid, "wrap"); + panel.add(projectId, "wrap"); + + UIUtils.addCopyAction(projectId); } { @@ -177,13 +200,26 @@ protected JComponent createContentsPane() { UIUtils.installInputValidator(fileListingsPath, new ExistingFileValidator(fileListingsPath, filter, false), this); } - if (!edit) { + if (!persisted) { fillValuesBasedOnGameType(projectType.getItemAt(0), projectType.getItemAt(0)); } return panel; } + @Nullable + @Override + protected JComponent createLeftButtonsPane() { + if (editable) { + return super.createLeftButtonsPane(); + } + return new JLabel( + "To edit this project's configuration, close it first", + UIManager.getIcon("Action.informationIcon"), + SwingConstants.CENTER + ); + } + @Nullable @Override protected JComponent getDefaultComponent() { @@ -191,7 +227,7 @@ protected JComponent getDefaultComponent() { } public void load(@NotNull ProjectContainer container) { - projectUuid.setText(container.getId().toString()); + projectId.setText(container.getId().toString()); projectName.setText(container.getName()); projectType.setSelectedItem(container.getType()); executableFilePath.setText(container.getExecutablePath().toString()); diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java index 1c9942d4f..e8adb5c58 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java @@ -42,7 +42,7 @@ public static class NewProjectItem extends MenuItem { @Override public void perform(@NotNull MenuItemContext ctx) { - final ProjectEditDialog dialog = new ProjectEditDialog(false); + final ProjectEditDialog dialog = new ProjectEditDialog(false, true); final ProjectContainer container = new ProjectContainer(UUID.randomUUID(), "New project", GameType.values()[0], Path.of(""), Path.of(""), Path.of(""), Path.of(""), Path.of("")); dialog.load(container); diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/navigator/menu/ProjectEditItem.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/navigator/menu/ProjectEditItem.java index 5837fc21d..37bdeb6fc 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/navigator/menu/ProjectEditItem.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/navigator/menu/ProjectEditItem.java @@ -1,5 +1,6 @@ package com.shade.decima.ui.navigator.menu; +import com.shade.decima.model.app.Project; import com.shade.decima.model.app.ProjectContainer; import com.shade.decima.model.app.ProjectManager; import com.shade.decima.ui.CommonDataKeys; @@ -21,12 +22,13 @@ public class ProjectEditItem extends MenuItem { @Override public void perform(@NotNull MenuItemContext ctx) { final ProjectContainer container = ctx.getData(CommonDataKeys.PROJECT_CONTAINER_KEY); + final Project project = ctx.getData(CommonDataKeys.PROJECT_KEY); if (container == null) { return; } - final ProjectEditDialog dialog = new ProjectEditDialog(true); + final ProjectEditDialog dialog = new ProjectEditDialog(true, project == null); dialog.load(container); @@ -36,11 +38,6 @@ public void perform(@NotNull MenuItemContext ctx) { } } - @Override - public boolean isEnabled(@NotNull MenuItemContext ctx) { - return ctx.getData(CommonDataKeys.PROJECT_KEY) == null; - } - @Override public boolean isVisible(@NotNull MenuItemContext ctx) { return ctx.getData(PlatformDataKeys.SELECTION_KEY) instanceof NavigatorProjectNode; diff --git a/modules/decima-ui/src/main/resources/icons/actions/copy.svg b/modules/decima-ui/src/main/resources/icons/actions/copy.svg new file mode 100644 index 000000000..37c372e44 --- /dev/null +++ b/modules/decima-ui/src/main/resources/icons/actions/copy.svg @@ -0,0 +1,10 @@ + + actions-copy + + + + + + + + diff --git a/modules/decima-ui/src/main/resources/icons/actions/information.svg b/modules/decima-ui/src/main/resources/icons/actions/information.svg new file mode 100644 index 000000000..ffbf6e695 --- /dev/null +++ b/modules/decima-ui/src/main/resources/icons/actions/information.svg @@ -0,0 +1,6 @@ + + actions-information + + + + diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/dialogs/BaseDialog.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/dialogs/BaseDialog.java index cbf159b60..15091a8e2 100644 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/dialogs/BaseDialog.java +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/dialogs/BaseDialog.java @@ -124,20 +124,39 @@ protected JComponent createButtonsPane() { panel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, UIColor.SHADOW)); } - final ButtonDescriptor[] leftButtons = getLeftButtons(); - final ButtonDescriptor[] rightButtons = getButtons(); - - if (leftButtons.length > 0) { - panel.add(createButtonsPane(leftButtons), "cell 0 0"); + final JComponent leftPane = createLeftButtonsPane(); + if (leftPane != null) { + panel.add(leftPane, "cell 0 0"); } - if (rightButtons.length > 0) { - panel.add(createButtonsPane(rightButtons), "cell 2 0"); + final JComponent rightPane = createRightButtonsPane(); + if (rightPane != null) { + panel.add(rightPane, "cell 2 0"); } return panel; } + @Nullable + protected JComponent createLeftButtonsPane() { + final ButtonDescriptor[] buttons = getLeftButtons(); + if (buttons.length > 0) { + return createButtonsPane(buttons); + } else { + return null; + } + } + + @Nullable + protected JComponent createRightButtonsPane() { + final ButtonDescriptor[] buttons = getButtons(); + if (buttons.length > 0) { + return createButtonsPane(buttons); + } else { + return null; + } + } + @NotNull private JComponent createButtonsPane(@NotNull ButtonDescriptor[] buttons) { final JPanel panel = new JPanel(); diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java index add1105b6..ad28cf942 100644 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java @@ -12,7 +12,9 @@ import javax.swing.plaf.basic.BasicSplitPaneUI; import javax.swing.tree.TreePath; import java.awt.*; +import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; import java.awt.event.*; import java.beans.PropertyChangeListener; import java.lang.reflect.Field; @@ -119,19 +121,6 @@ public static boolean isValid(@NotNull JComponent component) { return true; } - public static void addOpenAction(@NotNull JTextField component, @NotNull ActionListener delegate) { - final JToolBar toolBar = new JToolBar(); - - toolBar.add(new AbstractAction(null, UIManager.getIcon("Tree.openIcon")) { - @Override - public void actionPerformed(ActionEvent e) { - delegate.actionPerformed(e); - } - }); - - component.putClientProperty(FlatClientProperties.TEXT_FIELD_TRAILING_COMPONENT, toolBar); - } - public static void addOpenFileAction(@NotNull JTextField component, @NotNull String title, @Nullable FileFilter filter) { addOpenAction(component, e -> { final JFileChooser chooser = new JFileChooser(); @@ -146,6 +135,34 @@ public static void addOpenFileAction(@NotNull JTextField component, @NotNull Str }); } + public static void addOpenAction(@NotNull JTextField component, @NotNull ActionListener delegate) { + addAction(component, UIManager.getIcon("Tree.openIcon"), delegate); + } + + public static void addCopyAction(@NotNull JTextField component) { + addAction(component, UIManager.getIcon("Action.copyIcon"), e -> { + final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + final StringSelection contents = new StringSelection(component.getText()); + clipboard.setContents(contents, contents); + }); + } + + public static void addAction(@NotNull JTextField component, @NotNull Icon icon, @NotNull ActionListener delegate) { + final AbstractAction action = new AbstractAction(null, icon) { + @Override + public void actionPerformed(ActionEvent e) { + delegate.actionPerformed(e); + } + }; + action.setEnabled(component.isEnabled()); + + final JToolBar toolBar = new JToolBar(); + toolBar.add(action); + + component.putClientProperty(FlatClientProperties.TEXT_FIELD_TRAILING_COMPONENT, toolBar); + component.addPropertyChangeListener("enabled", e -> action.setEnabled(component.isEnabled())); + } + public static void addOpenDirectoryAction(@NotNull JTextField component, @NotNull String title) { addOpenAction(component, e -> { final JFileChooser chooser = new JFileChooser();