001package jmri.configurexml;
002
003import java.io.File;
004import java.util.Set;
005import java.awt.Component;
006import java.awt.event.ActionEvent;
007
008import javax.annotation.CheckForNull;
009import javax.annotation.Nonnull;
010import javax.swing.JFileChooser;
011
012import jmri.*;
013import jmri.jmrit.logixng.LogixNGPreferences;
014import jmri.jmrit.dispatcher.DispatcherFrame;
015import jmri.jmrit.display.Editor;
016import jmri.jmrit.display.EditorManager;
017import jmri.jmrit.logixng.LogixNG_Manager;
018import jmri.util.swing.JmriJOptionPane;
019
020/**
021 * Load configuration information from an XML file.
022 * <p>
023 * The file context for this is the "config" file chooser.
024 * <p>
025 * This will load whatever information types are present in the file. See
026 * {@link jmri.ConfigureManager} for information on the various types of
027 * information stored in configuration files.
028 *
029 * @author Bob Jacobsen Copyright (C) 2002
030 * @see jmri.jmrit.XmlFile
031 */
032public class LoadXmlConfigAction extends LoadStoreBaseAction {
033
034    public LoadXmlConfigAction() {
035        this("Open Data File ...");  // NOI18N
036    }
037
038    public LoadXmlConfigAction(String s) {
039        super(s);
040    }
041
042    @Override
043    public void actionPerformed(ActionEvent e) {
044        if (! InstanceManager.getDefault(PermissionManager.class)
045                .ensureAtLeastPermission(LoadAndStorePermissionOwner.LOAD_XML_FILE_PERMISSION,
046                        BooleanPermission.BooleanValue.TRUE)) {
047            return;
048        }
049        loadFile(getConfigFileChooser(), JmriJOptionPane.findWindowForObject( e == null ? null : e.getSource()));
050    }
051
052    /**
053     * Load a File from a given JFileChooser.
054     * @param fileChooser {@link JFileChooser} to use for file selection
055     * @param component a Component which has called the File Chooser.
056     * @return true if successful
057     */
058    protected boolean loadFile(@Nonnull JFileChooser fileChooser, @CheckForNull Component component ) {
059        Set<Editor> editors = InstanceManager.getDefault(EditorManager.class).getAll();
060        if (!editors.isEmpty()) {
061            InstanceManager.getDefault(jmri.UserPreferencesManager.class).showWarningMessage(
062                    Bundle.getMessage("DuplicateLoadTitle"), Bundle.getMessage("DuplicateLoadMessage"),  // NOI18N
063                    "jmri.jmrit.display.EditorManager",  "skipDupLoadDialog", false, true);  //NOI18N
064            InstanceManager.getDefault(jmri.UserPreferencesManager.class).setPreferenceItemDetails(
065                    "jmri.jmrit.display.EditorManager", "skipDupLoadDialog", Bundle.getMessage("DuplicateLoadSkip"));  // NOI18N
066        }
067
068        boolean results = false;
069        File file = getFile(fileChooser, component);
070        if (file != null) {
071            log.info("Loading selected file: {}", file); // NOI18N
072            try {
073                ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
074                if (cm == null) {
075                    log.error("Failed to get default configure manager");  // NOI18N
076                } else {
077                    results = cm.load(file);
078
079                    // If LogixNGs aren't setup, the actions and expressions will not
080                    // be stored if the user stores the tables and panels. So we need
081                    // to try to setup LogixNGs even if the loading failed.
082                    LogixNG_Manager logixNG_Manager = InstanceManager.getDefault(LogixNG_Manager.class);
083                    logixNG_Manager.setupAllLogixNGs();
084
085                    if (results) {
086                        // insure logix etc fire up
087                        InstanceManager.getDefault(jmri.LogixManager.class).activateAllLogixs();
088                        InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager.class).initializeLayoutBlockPaths();
089
090                        if (InstanceManager.getDefault(LogixNGPreferences.class).getStartLogixNGOnStartup()
091                                && logixNG_Manager.isStartLogixNGsOnLoad()) {
092                            logixNG_Manager.activateAllLogixNGs();
093                        }
094
095                        // If a LE panel specified "openDispatcher", it creates the DispatcherFrame instance.
096                        // The presence of the instance is use to trigger calling loadAtStartup after file loading is done.
097                        if (InstanceManager.isInitialized(DispatcherFrame.class)) {
098                            InstanceManager.getDefault(DispatcherFrame.class).loadAtStartup();
099                        }
100                    }
101                }
102            } catch (JmriException e) {
103                log.error("Unhandled problem in loadFile", e);  // NOI18N
104            }
105        } else {
106            results = true;   // We assume that as the file is null then the user has clicked cancel.
107        }
108        return results;
109    }
110
111    /**
112     * Get the File from a given JFileChooser.
113     * @return the selected File.
114     * @deprecated use {@link #getFile(JFileChooser fileChooser, Component component)}
115     * @param fileChooser the JFileChooser for the file.
116     */
117    @CheckForNull
118    @Deprecated (since="5.7.8",forRemoval=true)
119    public static File getFile(@Nonnull JFileChooser fileChooser) {
120        return getFile(fileChooser, null);
121    }
122
123    /**
124     * Get the File from an Open File JFileChooser.
125     * If a Component is provided, this helps the JFileChooser to not get stuck
126     * behind an Always On Top Window.
127     * @param fileChooser the FileChooser to get from.
128     * @param component a Component within a JFrame / Window / Popup Menu,
129     *                  or the JFrame or Window itself.
130     * @return the File, may be null if none selected.
131     */
132    @CheckForNull
133    public static File getFile(@Nonnull JFileChooser fileChooser, @CheckForNull Component component) {
134        fileChooser.setDialogType(javax.swing.JFileChooser.OPEN_DIALOG);
135        return getFileCustom(fileChooser, component);
136    }
137
138    /**
139     * @return the selected File.
140     * @deprecated use {@link #getFile(JFileChooser fileChooser, Component component)}
141     * @param fileChooser the FileChooser to get from.
142     */
143    @CheckForNull
144    @Deprecated (since="5.7.8",forRemoval=true)
145    public static File getFileCustom(@Nonnull JFileChooser fileChooser) {
146        return getFileCustom(fileChooser, null);
147    }
148
149    /**
150     * Get the File from a JFileChooser.
151     * If a Component is provided, this helps the JFileChooser to not get stuck
152     * behind an Always On Top Window.
153     * @param fileChooser the FileChooser to get from.
154     * @param component a Component within a JFrame / Window / Popup Menu,
155     *                  or the JFrame or Window itself.
156     * @return the File, may be null if none selected.
157     */
158    @CheckForNull
159    public static File getFileCustom(@Nonnull JFileChooser fileChooser, @CheckForNull Component component){
160        fileChooser.rescanCurrentDirectory();
161        int retVal = fileChooser.showDialog(component, Bundle.getMessage("MenuItemLoad"));  // NOI18N
162        if (retVal != JFileChooser.APPROVE_OPTION) {
163            return null;  // give up if no file selected
164        }
165        log.debug("Open file: {}", fileChooser.getSelectedFile().getPath());
166        return fileChooser.getSelectedFile();
167    }
168
169    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoadXmlConfigAction.class);
170
171}