All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.optaplanner.examples.common.swingui.SolverAndPersistenceFrame Maven / Gradle / Ivy

Go to download

OptaPlanner solves planning problems. This lightweight, embeddable planning engine implements powerful and scalable algorithms to optimize business resource scheduling and planning. This module contains the examples which demonstrate how to use it in a normal Java application.

There is a newer version: 9.44.0.Final
Show newest version
package org.optaplanner.examples.common.swingui;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.LayoutStyle;
import javax.swing.ListSelectionModel;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileFilter;

import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.score.Score;
import org.optaplanner.examples.common.app.CommonApp;
import org.optaplanner.examples.common.business.SolutionBusiness;
import org.optaplanner.examples.common.persistence.AbstractSolutionExporter;
import org.optaplanner.examples.common.persistence.AbstractSolutionImporter;
import org.optaplanner.swing.impl.TangoColorFactory;

/**
 * @param  the solution type, the class with the {@link PlanningSolution} annotation
 */
public final class SolverAndPersistenceFrame
        extends JFrame {

    public static final ImageIcon OPTAPLANNER_ICON = new ImageIcon(
            SolverAndPersistenceFrame.class.getResource("optaPlannerIcon.png"));

    private final SolutionBusiness solutionBusiness;
    private final ImageIcon indictmentHeatMapTrueIcon;
    private final ImageIcon indictmentHeatMapFalseIcon;
    private final ImageIcon refreshScreenDuringSolvingTrueIcon;
    private final ImageIcon refreshScreenDuringSolvingFalseIcon;

    private final SolutionPanel solutionPanel;
    private final ConstraintMatchesDialog constraintMatchesDialog;

    private JList quickOpenUnsolvedJList;
    private JList quickOpenSolvedJList;
    private Action openAction;
    private Action saveAction;
    private Action importAction;
    private Action exportAction;
    private final Action[] extraActions;
    private JToggleButton refreshScreenDuringSolvingToggleButton;
    private JToggleButton indictmentHeatMapToggleButton;
    private Action solveAction;
    private JButton solveButton;
    private Action terminateSolvingEarlyAction;
    private JButton terminateSolvingEarlyButton;
    private JPanel middlePanel;
    private JProgressBar progressBar;
    private JTextField scoreField;
    private ShowConstraintMatchesDialogAction showConstraintMatchesDialogAction;

    public SolverAndPersistenceFrame(SolutionBusiness solutionBusiness,
            SolutionPanel solutionPanel, CommonApp.ExtraAction[] extraActions) {
        super(solutionBusiness.getAppName() + " OptaPlanner example");
        this.solutionBusiness = solutionBusiness;
        this.solutionPanel = solutionPanel;
        setIconImage(OPTAPLANNER_ICON.getImage());
        solutionPanel.setSolutionBusiness(solutionBusiness);
        solutionPanel.setSolverAndPersistenceFrame(this);
        this.extraActions = Arrays.stream(extraActions)
                .map(a -> new AbstractAction(a.getName()) {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        a.accept(solutionBusiness, solutionPanel);
                    }
                })
                .toArray(Action[]::new);
        indictmentHeatMapTrueIcon = new ImageIcon(getClass().getResource("indictmentHeatMapTrueIcon.png"));
        indictmentHeatMapFalseIcon = new ImageIcon(getClass().getResource("indictmentHeatMapFalseIcon.png"));
        refreshScreenDuringSolvingTrueIcon = new ImageIcon(getClass().getResource("refreshScreenDuringSolvingTrueIcon.png"));
        refreshScreenDuringSolvingFalseIcon = new ImageIcon(getClass().getResource("refreshScreenDuringSolvingFalseIcon.png"));
        registerListeners();
        constraintMatchesDialog = new ConstraintMatchesDialog(this, solutionBusiness);
    }

    private void registerListeners() {
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                // This async, so it doesn't stop the solving immediately
                solutionBusiness.close();
            }
        });
    }

    private void bestSolutionChanged(Solution_ solution) {
        Score score = solutionBusiness.getScore();
        if (refreshScreenDuringSolvingToggleButton.isSelected()) {
            solutionPanel.updatePanel(solution);
            validate(); // TODO remove me?
        }
        refreshScoreField(score);
    }

    public void init(Component centerForComponent) {
        setContentPane(createContentPane());
        pack();
        setLocationRelativeTo(centerForComponent);
    }

    private JComponent createContentPane() {
        JComponent quickOpenPanel = createQuickOpenPanel();
        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(createToolBar(), BorderLayout.NORTH);
        mainPanel.add(createMiddlePanel(), BorderLayout.CENTER);
        mainPanel.add(createScorePanel(), BorderLayout.SOUTH);
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, quickOpenPanel, mainPanel);
        splitPane.setOneTouchExpandable(true);
        splitPane.setResizeWeight(0.2);
        return splitPane;
    }

    private JComponent createQuickOpenPanel() {
        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                createQuickOpenUnsolvedPanel(), createQuickOpenSolvedPanel());
        splitPane.setResizeWeight(0.8);
        splitPane.setBorder(null);
        return splitPane;
    }

    private JComponent createQuickOpenUnsolvedPanel() {
        quickOpenUnsolvedJList = new JList<>(new DefaultListModel<>());
        List unsolvedFileList = solutionBusiness.getUnsolvedFileList();
        return createQuickOpenPanel(quickOpenUnsolvedJList, "Unsolved dataset shortcuts", unsolvedFileList);
    }

    private JComponent createQuickOpenSolvedPanel() {
        quickOpenSolvedJList = new JList<>(new DefaultListModel<>());
        List solvedFileList = solutionBusiness.getSolvedFileList();
        return createQuickOpenPanel(quickOpenSolvedJList, "Solved dataset shortcuts", solvedFileList);
    }

    private JComponent createQuickOpenPanel(JList listPanel, String title, List fileList) {
        listPanel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listPanel.addListSelectionListener(event -> {
            if (event.getValueIsAdjusting()) {
                return;
            }
            int selectedIndex = listPanel.getSelectedIndex();
            if (selectedIndex < 0) {
                return;
            }
            QuickOpenAction action = listPanel.getModel().getElementAt(selectedIndex);
            action.actionPerformed(new ActionEvent(listPanel, -1, null));
        });

        refreshQuickOpenPanel(listPanel, fileList);

        JScrollPane scrollPane = new JScrollPane(listPanel);
        scrollPane.getVerticalScrollBar().setUnitIncrement(25);
        scrollPane.setMinimumSize(new Dimension(100, 80));
        // Size fits into screen resolution 1024*768
        scrollPane.setPreferredSize(new Dimension(180, 200));

        JPanel titlePanel = new JPanel(new BorderLayout());
        titlePanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        JLabel titleLabel = new JLabel(title);
        titleLabel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
        titlePanel.add(titleLabel, BorderLayout.NORTH);
        titlePanel.add(scrollPane, BorderLayout.CENTER);
        return titlePanel;
    }

    private void refreshQuickOpenPanel(JList listPanel, List fileList) {
        DefaultListModel model = (DefaultListModel) listPanel.getModel();
        model.clear();

        for (File file : fileList) {
            QuickOpenAction action = new QuickOpenAction(file);
            model.addElement(action);
            listPanel.clearSelection();
        }
    }

    private class QuickOpenAction extends AbstractAction {

        private final File file;

        public QuickOpenAction(File file) {
            super(file.getName().replaceAll("\\.json$|\\.xml$", ""));
            this.file = file;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            try {
                solutionBusiness.openSolution(file);
                setSolutionLoaded(e.getSource());
            } finally {
                setCursor(Cursor.getDefaultCursor());
            }
        }

        @Override
        public String toString() {
            return getValue(Action.NAME).toString();
        }

    }

    private JComponent createToolBar() {
        // JToolBar looks ugly in Nimbus LookAndFeel
        JPanel toolBar = new JPanel();
        GroupLayout toolBarLayout = new GroupLayout(toolBar);
        toolBar.setLayout(toolBarLayout);

        JButton importButton;
        if (solutionBusiness.hasImporter()) {
            importAction = new ImportAction();
            importButton = new JButton(importAction);
        } else {
            importButton = null;
        }
        openAction = new OpenAction();
        openAction.setEnabled(true);
        JButton openButton = new JButton(openAction);
        saveAction = new SaveAction();
        saveAction.setEnabled(false);
        JButton saveButton = new JButton(saveAction);
        JButton exportButton;
        if (solutionBusiness.hasExporter()) {
            exportAction = new ExportAction();
            exportAction.setEnabled(false);
            exportButton = new JButton(exportAction);
        } else {
            exportButton = null;
        }
        JButton[] extraButtons = new JButton[extraActions.length];
        for (int i = 0; i < extraActions.length; i++) {
            extraButtons[i] = new JButton(extraActions[i]);
        }

        progressBar = new JProgressBar(0, 100);

        JPanel solvePanel = new JPanel(new CardLayout());
        solveAction = new SolveAction();
        solveAction.setEnabled(false);
        solveButton = new JButton(solveAction);
        terminateSolvingEarlyAction = new TerminateSolvingEarlyAction();
        terminateSolvingEarlyAction.setEnabled(false);
        terminateSolvingEarlyButton = new JButton(terminateSolvingEarlyAction);
        terminateSolvingEarlyButton.setVisible(false);
        solvePanel.add(solveButton, "solveAction");
        solvePanel.add(terminateSolvingEarlyButton, "terminateSolvingEarlyAction");
        solveButton.setMinimumSize(terminateSolvingEarlyButton.getMinimumSize());
        solveButton.setPreferredSize(terminateSolvingEarlyButton.getPreferredSize());

        GroupLayout.SequentialGroup horizontalGroup = toolBarLayout.createSequentialGroup();
        if (solutionBusiness.hasImporter()) {
            horizontalGroup.addComponent(importButton);
        }
        horizontalGroup.addComponent(openButton);
        horizontalGroup.addComponent(saveButton);
        if (solutionBusiness.hasExporter()) {
            horizontalGroup.addComponent(exportButton);
        }
        for (JButton extraButton : extraButtons) {
            horizontalGroup.addComponent(extraButton);
        }
        horizontalGroup.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED,
                GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
        horizontalGroup.addComponent(solvePanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE,
                GroupLayout.PREFERRED_SIZE);
        horizontalGroup.addComponent(progressBar, 20, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
        toolBarLayout.setHorizontalGroup(horizontalGroup);
        GroupLayout.ParallelGroup verticalGroup = toolBarLayout.createParallelGroup(GroupLayout.Alignment.CENTER);
        if (solutionBusiness.hasImporter()) {
            verticalGroup.addComponent(importButton);
        }
        verticalGroup.addComponent(openButton);
        verticalGroup.addComponent(saveButton);
        if (solutionBusiness.hasExporter()) {
            verticalGroup.addComponent(exportButton);
        }
        for (JButton extraButton : extraButtons) {
            verticalGroup.addComponent(extraButton);
        }
        verticalGroup.addComponent(solvePanel);
        verticalGroup.addComponent(progressBar);
        toolBarLayout.setVerticalGroup(verticalGroup);
        return toolBar;
    }

    private class SolveAction extends AbstractAction {

        public SolveAction() {
            super("Solve", new ImageIcon(SolverAndPersistenceFrame.class.getResource("solveAction.png")));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setSolvingState(true);
            Solution_ problem = solutionBusiness.getSolution();
            new SolveWorker(problem).execute();
        }

    }

    protected class SolveWorker extends SwingWorker {

        protected final Solution_ problem;

        public SolveWorker(Solution_ problem) {
            this.problem = problem;
        }

        @Override
        protected Solution_ doInBackground() {
            return solutionBusiness.solve(problem, SolverAndPersistenceFrame.this::bestSolutionChanged);
        }

        @Override
        protected void done() {
            try {
                Solution_ bestSolution = get();
                solutionBusiness.setSolution(bestSolution);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new IllegalStateException("Solving was interrupted.", e);
            } catch (ExecutionException e) {
                throw new IllegalStateException("Solving failed.", e.getCause());
            } finally {
                setSolvingState(false);
                resetScreen();
            }
        }

    }

    private class TerminateSolvingEarlyAction extends AbstractAction {

        public TerminateSolvingEarlyAction() {
            super("Terminate solving early",
                    new ImageIcon(SolverAndPersistenceFrame.class.getResource("terminateSolvingEarlyAction.png")));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            terminateSolvingEarlyAction.setEnabled(false);
            progressBar.setString("Terminating...");
            // This async, so it doesn't stop the solving immediately
            solutionBusiness.terminateSolvingEarly();
        }

    }

    private class OpenAction extends AbstractAction {

        private static final String NAME = "Open...";
        private final JFileChooser fileChooser;

        public OpenAction() {
            super(NAME, new ImageIcon(SolverAndPersistenceFrame.class.getResource("openAction.png")));
            fileChooser = new JFileChooser(solutionBusiness.getSolvedDataDir());
            final String inputFileExtension = solutionBusiness.getSolutionFileIO().getOutputFileExtension();
            fileChooser.setFileFilter(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    return file.isDirectory() || file.getName().endsWith("." + inputFileExtension);
                }

                @Override
                public String getDescription() {
                    return "Solution files (*." + inputFileExtension + ")";
                }
            });
            fileChooser.setDialogTitle(NAME);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            int approved = fileChooser.showOpenDialog(SolverAndPersistenceFrame.this);
            if (approved == JFileChooser.APPROVE_OPTION) {
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    solutionBusiness.openSolution(fileChooser.getSelectedFile());
                    setSolutionLoaded(e.getSource());
                } finally {
                    setCursor(Cursor.getDefaultCursor());
                }
            }
        }

    }

    private class SaveAction extends AbstractAction {

        private static final String NAME = "Save as...";
        private JFileChooser fileChooser;

        public SaveAction() {
            super(NAME, new ImageIcon(SolverAndPersistenceFrame.class.getResource("saveAction.png")));
            fileChooser = new JFileChooser(solutionBusiness.getSolvedDataDir());
            final String outputFileExtension = solutionBusiness.getSolutionFileIO().getOutputFileExtension();
            fileChooser.setFileFilter(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    return file.isDirectory() || file.getName().endsWith("." + outputFileExtension);
                }

                @Override
                public String getDescription() {
                    return "Solution files (*." + outputFileExtension + ")";
                }
            });
            fileChooser.setDialogTitle(NAME);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            final String outputFileExtension = solutionBusiness.getSolutionFileIO().getOutputFileExtension();
            fileChooser.setSelectedFile(new File(solutionBusiness.getSolvedDataDir(),
                    SolutionBusiness.getBaseFileName(solutionBusiness.getSolutionFileName()) + "." + outputFileExtension));
            int approved = fileChooser.showSaveDialog(SolverAndPersistenceFrame.this);
            if (approved == JFileChooser.APPROVE_OPTION) {
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    solutionBusiness.saveSolution(fileChooser.getSelectedFile());
                } finally {
                    setCursor(Cursor.getDefaultCursor());
                }
                refreshQuickOpenPanel(quickOpenUnsolvedJList, solutionBusiness.getUnsolvedFileList());
                refreshQuickOpenPanel(quickOpenSolvedJList, solutionBusiness.getSolvedFileList());
                SolverAndPersistenceFrame.this.validate();
            }
        }

    }

    private class ImportAction extends AbstractAction {

        private static final String NAME = "Import...";
        private final JFileChooser fileChooser;

        public ImportAction() {
            super(NAME, new ImageIcon(SolverAndPersistenceFrame.class.getResource("importAction.png")));
            if (!solutionBusiness.hasImporter()) {
                fileChooser = null;
                return;
            }
            fileChooser = new JFileChooser(solutionBusiness.getImportDataDir());
            boolean firstFilter = true;
            for (final AbstractSolutionImporter importer : solutionBusiness.getImporters()) {
                FileFilter filter = new FileFilter() {
                    @Override
                    public boolean accept(File file) {
                        return file.isDirectory() || importer.acceptInputFile(file);
                    }

                    @Override
                    public String getDescription() {
                        return "Import files (*." + importer.getInputFileSuffix() + ")";
                    }
                };
                fileChooser.addChoosableFileFilter(filter);
                if (firstFilter) {
                    fileChooser.setFileFilter(filter);
                    firstFilter = false;
                }
            }
            fileChooser.setDialogTitle(NAME);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            int approved = fileChooser.showOpenDialog(SolverAndPersistenceFrame.this);
            if (approved == JFileChooser.APPROVE_OPTION) {
                File file = fileChooser.getSelectedFile();
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    solutionBusiness.importSolution(file);
                    setSolutionLoaded(e.getSource());
                } finally {
                    setCursor(Cursor.getDefaultCursor());
                }
            }
        }

    }

    private class ExportAction extends AbstractAction {

        private static final String NAME = "Export as...";
        private final JFileChooser fileChooser;

        public ExportAction() {
            super(NAME, new ImageIcon(SolverAndPersistenceFrame.class.getResource("exportAction.png")));
            if (!solutionBusiness.hasExporter()) {
                fileChooser = null;
                return;
            }
            fileChooser = new JFileChooser(solutionBusiness.getExportDataDir());
            for (AbstractSolutionExporter exporter : solutionBusiness.getExporters()) {
                fileChooser.addChoosableFileFilter(new ExporterFileFilter(exporter));
            }
            fileChooser.setDialogTitle(NAME);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            fileChooser.setAcceptAllFileFilterUsed(false);
            fileChooser.addPropertyChangeListener(
                    new FileNameSetter(fileChooser,
                            solutionBusiness.getExportDataDir(),
                            SolutionBusiness.getBaseFileName(solutionBusiness.getSolutionFileName())));
            int approved = fileChooser.showSaveDialog(SolverAndPersistenceFrame.this);
            if (approved == JFileChooser.APPROVE_OPTION) {
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    AbstractSolutionExporter exporter =
                            ((ExporterFileFilter) fileChooser.getFileFilter()).getExporter();
                    File exportFile = fileChooser.getSelectedFile();
                    solutionBusiness.exportSolution(exporter, exportFile);
                } finally {
                    setCursor(Cursor.getDefaultCursor());
                }
            }
            // Reset file name
            fileChooser.setSelectedFile(null);
        }

    }

    private JPanel createMiddlePanel() {
        middlePanel = new JPanel(new CardLayout());
        JPanel usageExplanationPanel = new JPanel(new BorderLayout(5, 5));
        ImageIcon usageExplanationIcon = new ImageIcon(getClass().getResource(solutionPanel.getUsageExplanationPath()));
        JLabel usageExplanationLabel = new JLabel(usageExplanationIcon);
        // Allow splitPane divider to be moved to the right
        usageExplanationLabel.setMinimumSize(new Dimension(100, 100));
        usageExplanationPanel.add(usageExplanationLabel, BorderLayout.CENTER);
        JPanel descriptionPanel = new JPanel(new BorderLayout(2, 2));
        descriptionPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        descriptionPanel.add(new JLabel("Example description"), BorderLayout.NORTH);
        JTextArea descriptionTextArea = new JTextArea(8, 70);
        descriptionTextArea.setEditable(false);
        descriptionTextArea.setText(solutionBusiness.getAppDescription());
        descriptionPanel.add(new JScrollPane(descriptionTextArea,
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER);
        usageExplanationPanel.add(descriptionPanel, BorderLayout.SOUTH);
        middlePanel.add(usageExplanationPanel, "usageExplanationPanel");
        JComponent wrappedSolutionPanel;
        if (solutionPanel.isWrapInScrollPane()) {
            wrappedSolutionPanel = new JScrollPane(solutionPanel);
        } else {
            wrappedSolutionPanel = solutionPanel;
        }
        middlePanel.add(wrappedSolutionPanel, "solutionPanel");
        return middlePanel;
    }

    private JPanel createScorePanel() {
        JPanel scorePanel = new JPanel(new BorderLayout(5, 0));
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        showConstraintMatchesDialogAction = new ShowConstraintMatchesDialogAction();
        showConstraintMatchesDialogAction.setEnabled(false);
        buttonPanel.add(new JButton(showConstraintMatchesDialogAction));
        indictmentHeatMapToggleButton = new JToggleButton(
                solutionPanel.isUseIndictmentColor() ? indictmentHeatMapTrueIcon : indictmentHeatMapFalseIcon,
                solutionPanel.isUseIndictmentColor());
        indictmentHeatMapToggleButton.setEnabled(false);
        indictmentHeatMapToggleButton.setToolTipText("Show indictment heat map");
        indictmentHeatMapToggleButton.addActionListener(e -> {
            boolean selected = indictmentHeatMapToggleButton.isSelected();
            indictmentHeatMapToggleButton.setIcon(selected ? indictmentHeatMapTrueIcon : indictmentHeatMapFalseIcon);
            solutionPanel.setUseIndictmentColor(selected);
            resetScreen();
        });
        buttonPanel.add(indictmentHeatMapToggleButton);
        scorePanel.add(buttonPanel, BorderLayout.WEST);
        scoreField = new JTextField("Score:");
        scoreField.setEditable(false);
        scoreField.setForeground(Color.BLACK);
        scoreField.setBorder(BorderFactory.createLoweredBevelBorder());
        scorePanel.add(scoreField, BorderLayout.CENTER);
        refreshScreenDuringSolvingToggleButton = new JToggleButton(refreshScreenDuringSolvingTrueIcon, true);
        refreshScreenDuringSolvingToggleButton.setToolTipText("Refresh screen during solving");
        refreshScreenDuringSolvingToggleButton.addActionListener(e -> {
            refreshScreenDuringSolvingToggleButton
                    .setIcon(refreshScreenDuringSolvingToggleButton.isSelected() ? refreshScreenDuringSolvingTrueIcon
                            : refreshScreenDuringSolvingFalseIcon);
        });
        scorePanel.add(refreshScreenDuringSolvingToggleButton, BorderLayout.EAST);
        return scorePanel;
    }

    private class ShowConstraintMatchesDialogAction extends AbstractAction {

        public ShowConstraintMatchesDialogAction() {
            super("Constraint matches",
                    new ImageIcon(SolverAndPersistenceFrame.class.getResource("showConstraintMatchesDialogAction.png")));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            constraintMatchesDialog.resetContentPanel();
            constraintMatchesDialog.setVisible(true);
        }

    }

    public void setSolutionLoaded(Object eventSource) {
        if (eventSource != quickOpenUnsolvedJList) {
            quickOpenUnsolvedJList.clearSelection();
        }
        if (eventSource != quickOpenSolvedJList) {
            quickOpenSolvedJList.clearSelection();
        }
        setTitle(solutionBusiness.getAppName() + " - " + solutionBusiness.getSolutionFileName());
        ((CardLayout) middlePanel.getLayout()).show(middlePanel, "solutionPanel");
        setSolvingState(false);
        resetScreen();
    }

    private void setSolvingState(boolean solving) {
        quickOpenUnsolvedJList.setEnabled(!solving);
        quickOpenSolvedJList.setEnabled(!solving);
        if (solutionBusiness.hasImporter()) {
            importAction.setEnabled(!solving);
        }
        openAction.setEnabled(!solving);
        saveAction.setEnabled(!solving);
        if (solutionBusiness.hasExporter()) {
            exportAction.setEnabled(!solving);
        }
        solveAction.setEnabled(!solving);
        solveButton.setVisible(!solving);
        terminateSolvingEarlyAction.setEnabled(solving);
        terminateSolvingEarlyButton.setVisible(solving);
        if (solving) {
            terminateSolvingEarlyButton.requestFocus();
        } else {
            solveButton.requestFocus();
        }
        solutionPanel.setEnabled(!solving);
        progressBar.setIndeterminate(solving);
        progressBar.setStringPainted(solving);
        progressBar.setString(solving ? "Solving..." : null);
        indictmentHeatMapToggleButton.setEnabled(solutionPanel.isIndictmentHeatMapEnabled() && !solving);
        showConstraintMatchesDialogAction.setEnabled(!solving);
    }

    public void resetScreen() {
        Solution_ solution = solutionBusiness.getSolution();
        Score score = solutionBusiness.getScore();
        solutionPanel.resetPanel(solution);
        validate();
        refreshScoreField(score);
    }

    public void refreshScoreField(Score score) {
        scoreField.setForeground(determineScoreFieldForeground(score));
        scoreField.setText("Latest best score: " + score);
    }

    private Color determineScoreFieldForeground(Score score) {
        if (!score.isSolutionInitialized()) {
            return TangoColorFactory.SCARLET_3;
        } else {
            return score.isFeasible() ? TangoColorFactory.CHAMELEON_3 : TangoColorFactory.ORANGE_3;
        }
    }

    private final class ExporterFileFilter extends FileFilter {
        private final AbstractSolutionExporter exporter;

        public ExporterFileFilter(AbstractSolutionExporter exporter) {
            this.exporter = exporter;
        }

        @Override
        public boolean accept(File file) {
            return file.isDirectory() || file.getName().endsWith("." + exporter.getOutputFileSuffix());
        }

        @Override
        public String getDescription() {
            return "Export files (*." + exporter.getOutputFileSuffix() + ")";
        }

        public AbstractSolutionExporter getExporter() {
            return exporter;
        }
    }

    // Does the creation of the file name + setting it in the file chooser
    private final class FileNameSetter implements PropertyChangeListener {

        private JFileChooser fileChooser;
        private File exportDataDir;
        private String baseName;

        public FileNameSetter(JFileChooser fileChooser, File exportDataDir, String baseName) {

            this.fileChooser = fileChooser;
            this.exportDataDir = exportDataDir;
            this.baseName = baseName;

            setFileName();
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            String prop = evt.getPropertyName();

            //If a file became selected, find out which one.
            if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) {
                File file = (File) evt.getNewValue();
                if (file == null) {
                    setFileName();
                }
            } else if (prop.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
                setFileName();
            }
        }

        void setFileName() {
            AbstractSolutionExporter exporter = ((ExporterFileFilter) fileChooser.getFileFilter()).getExporter();
            fileChooser.setSelectedFile(
                    new File(this.exportDataDir, this.baseName + "." + exporter.getOutputFileSuffix()));
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy