001package jmri.jmrit.logixng.tools.swing;
002
003import java.awt.Component;
004import java.awt.Toolkit;
005import java.awt.event.ActionEvent;
006import java.awt.event.KeyEvent;
007import java.beans.PropertyVetoException;
008import java.text.MessageFormat;
009import java.util.ArrayList;
010import java.util.List;
011
012import javax.swing.*;
013
014import jmri.Manager;
015import jmri.NamedBean;
016import jmri.Reference;
017import jmri.util.swing.JmriJOptionPane;
018
019/**
020 * Helper class for deleting a bean
021 *
022 * @author Daniel Bergqvist (C) 2022
023 *
024 * @param <E> the type of NamedBean supported by this model
025 */
026public class DeleteBean<E extends NamedBean> {
027
028    private final Manager<E> _manager;
029
030    public DeleteBean(Manager<E> manager) {
031        _manager = manager;
032    }
033
034    public void delete(
035            final E x,
036            boolean hasChildren,
037            DeleteTask<E> deleteTask,
038            GetListenersRef<E> getListenersRef,
039            String className) {
040        delete(x, hasChildren, deleteTask, getListenersRef, className, false);
041    }
042
043    public boolean delete(
044            final E x,
045            boolean hasChildren,
046            DeleteTask<E> deleteTask,
047            GetListenersRef<E> getListenersRef,
048            String className,
049            boolean modal) {
050
051        final Reference<Boolean> reference = new Reference<>(false);
052        final jmri.UserPreferencesManager p;
053        p = jmri.InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class);
054
055        StringBuilder message = new StringBuilder();
056        try {
057            _manager.deleteBean(x, "CanDelete");  // NOI18N
058        } catch (PropertyVetoException e) {
059            if (e.getPropertyChangeEvent().getPropertyName().equals("DoNotDelete")) { // NOI18N
060                log.warn("{} : Do Not Delete", e.getMessage());
061                message.append(Bundle.getMessage("VetoDeleteBean", x.getBeanType(), x.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME), e.getMessage()));
062                JmriJOptionPane.showMessageDialog(null, message.toString(),
063                        Bundle.getMessage("QuestionTitle"),
064                        JmriJOptionPane.ERROR_MESSAGE);
065                return false;
066            }
067            message.append(e.getMessage());
068        }
069        List<String> listenerRefs = new ArrayList<>();
070        getListenersRef.getListenerRefsIncludingChildren(x, listenerRefs);
071        int listenerRefsCount = listenerRefs.size();
072        log.debug("Delete with {}", listenerRefsCount);
073        if (p != null && p.getMultipleChoiceOption(className, "delete") == 0x02 && message.toString().isEmpty()) {
074            deleteTask.deleteBean(x);
075        } else {
076            final JDialog dialog = new JDialog((JFrame)null, modal);
077            dialog.setTitle(Bundle.getMessage("QuestionTitle"));
078            dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
079            JPanel container = new JPanel();
080            container.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
081            container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
082
083            if (listenerRefsCount > 0) { // warn of listeners attached before delete
084                String prompt = hasChildren
085                        ? "DeleteWithChildrenPrompt" : "DeletePrompt";
086                JLabel question = new JLabel(Bundle.getMessage(prompt, x.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME)));
087                question.setAlignmentX(Component.CENTER_ALIGNMENT);
088                container.add(question);
089
090                ArrayList<String> listeners = new ArrayList<>();
091                for (String listenerRef : listenerRefs) {
092                    if (!listeners.contains(listenerRef)) {
093                        listeners.add(listenerRef);
094                    }
095                }
096
097                message.append("<br>");
098                message.append(Bundle.getMessage("ReminderInUse", listenerRefsCount));
099                message.append("<ul>");
100                for (String listener : listeners) {
101                    message.append("<li>");
102                    message.append(listener);
103                    message.append("</li>");
104                }
105                message.append("</ul>");
106
107                JEditorPane pane = new JEditorPane();
108                pane.setContentType("text/html");
109                pane.setText("<html>" + message.toString() + "</html>");
110                pane.setEditable(false);
111                JScrollPane jScrollPane = new JScrollPane(pane);
112                container.add(jScrollPane);
113            } else {
114                String prompt = hasChildren
115                        ? "DeleteWithChildrenPrompt" : "DeletePrompt";
116                String msg = MessageFormat.format(
117                        Bundle.getMessage(prompt), x.getSystemName());
118                JLabel question = new JLabel(msg);
119                question.setAlignmentX(Component.CENTER_ALIGNMENT);
120                container.add(question);
121            }
122
123            final JCheckBox remember = new JCheckBox(Bundle.getMessage("MessageRememberSetting"));
124            remember.setFont(remember.getFont().deriveFont(10f));
125            remember.setAlignmentX(Component.CENTER_ALIGNMENT);
126
127            JButton yesButton = new JButton(Bundle.getMessage("ButtonYes"));
128            JButton noButton = new JButton(Bundle.getMessage("ButtonNo"));
129            JPanel button = new JPanel();
130            button.setAlignmentX(Component.CENTER_ALIGNMENT);
131            button.add(yesButton);
132            button.add(noButton);
133            container.add(button);
134
135            noButton.addActionListener((ActionEvent e) -> {
136                //there is no point in remembering this the user will never be
137                //able to delete a bean!
138                reference.set(false);
139                dialog.dispose();
140            });
141
142            yesButton.addActionListener((ActionEvent e) -> {
143                if (remember.isSelected() && p != null) {
144                    p.setMultipleChoiceOption(className, "delete", 0x02);  // NOI18N
145                }
146                deleteTask.deleteBean(x);
147                reference.set(true);
148                dialog.dispose();
149            });
150            container.add(remember);
151            container.setAlignmentX(Component.CENTER_ALIGNMENT);
152            container.setAlignmentY(Component.CENTER_ALIGNMENT);
153            dialog.getContentPane().add(container);
154            dialog.pack();
155
156            dialog.getRootPane().setDefaultButton(noButton);
157            noButton.requestFocusInWindow(); // set default keyboard focus, after pack() before setVisible(true)
158            dialog.getRootPane().registerKeyboardAction(e -> { // escape to exit
159                    dialog.setVisible(false);
160                    dialog.dispose(); },
161                KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
162
163            dialog.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width) / 2 - dialog.getWidth() / 2,
164                    (Toolkit.getDefaultToolkit().getScreenSize().height) / 2 - dialog.getHeight() / 2);
165            dialog.setModal(true);
166            dialog.setVisible(true);
167        }
168        Boolean result = reference.get();
169        return result != null && result;
170    }
171
172
173    public interface DeleteTask<T> {
174        void deleteBean(T bean);
175    }
176
177
178    public interface GetListenersRef<T> {
179        void getListenerRefsIncludingChildren(T bean, List<String> list);
180    }
181
182
183    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DeleteBean.class);
184}