/*
* Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.optaplanner.examples.common.swingui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.List;
import javax.swing.JPanel;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.api.score.constraint.ConstraintMatch;
import org.optaplanner.core.api.score.constraint.Indictment;
import org.optaplanner.core.impl.solver.ProblemFactChange;
import org.optaplanner.examples.common.business.SolutionBusiness;
import org.optaplanner.swing.impl.TangoColorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
*/
public abstract class SolutionPanel<Solution_> extends JPanel implements Scrollable {
protected static final String USAGE_EXPLANATION_PATH = "/org/optaplanner/examples/common/swingui/exampleUsageExplanation.png";
// Size fits into screen resolution 1024*768
public static final Dimension PREFERRED_SCROLLABLE_VIEWPORT_SIZE = new Dimension(800, 600);
protected static final Color[][] INDICTMENT_COLORS = {
{TangoColorFactory.SCARLET_3, TangoColorFactory.SCARLET_1},
{TangoColorFactory.ORANGE_3, TangoColorFactory.ORANGE_1},
{TangoColorFactory.BUTTER_3, TangoColorFactory.BUTTER_1},
{TangoColorFactory.CHAMELEON_3, TangoColorFactory.CHAMELEON_1},
{TangoColorFactory.SKY_BLUE_3, TangoColorFactory.SKY_BLUE_1},
{TangoColorFactory.PLUM_3, TangoColorFactory.PLUM_1}
};
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
protected SolverAndPersistenceFrame solverAndPersistenceFrame;
protected SolutionBusiness<Solution_> solutionBusiness;
protected boolean useIndictmentColor = false;
protected TangoColorFactory normalColorFactory;
protected double[] indictmentMinimumLevelNumbers;
public SolverAndPersistenceFrame getSolverAndPersistenceFrame() {
return solverAndPersistenceFrame;
}
public void setSolverAndPersistenceFrame(SolverAndPersistenceFrame solverAndPersistenceFrame) {
this.solverAndPersistenceFrame = solverAndPersistenceFrame;
}
public SolutionBusiness<Solution_> getSolutionBusiness() {
return solutionBusiness;
}
public void setSolutionBusiness(SolutionBusiness<Solution_> solutionBusiness) {
this.solutionBusiness = solutionBusiness;
}
public boolean isUseIndictmentColor() {
return useIndictmentColor;
}
public void setUseIndictmentColor(boolean useIndictmentColor) {
this.useIndictmentColor = useIndictmentColor;
}
public String getUsageExplanationPath() {
return USAGE_EXPLANATION_PATH;
}
public boolean isWrapInScrollPane() {
return true;
}
public abstract void resetPanel(Solution_ solution);
public void updatePanel(Solution_ solution) {
resetPanel(solution);
}
public Solution_ getSolution() {
return (Solution_) solutionBusiness.getSolution();
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return PREFERRED_SCROLLABLE_VIEWPORT_SIZE;
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 20;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 20;
}
@Override
public boolean getScrollableTracksViewportWidth() {
if (getParent() instanceof JViewport) {
return (((JViewport) getParent()).getWidth() > getPreferredSize().width);
}
return false;
}
@Override
public boolean getScrollableTracksViewportHeight() {
if (getParent() instanceof JViewport) {
return (((JViewport) getParent()).getHeight() > getPreferredSize().height);
}
return false;
}
public boolean isIndictmentHeatMapEnabled() {
return false;
}
protected void preparePlanningEntityColors(List<?> planningEntityList) {
if (useIndictmentColor) {
indictmentMinimumLevelNumbers = null;
for (Object planningEntity : planningEntityList) {
Indictment indictment = solutionBusiness.getIndictmentMap().get(planningEntity);
if (indictment != null) {
Number[] levelNumbers = indictment.getScoreTotal().toLevelNumbers();
if (indictmentMinimumLevelNumbers == null) {
indictmentMinimumLevelNumbers = new double[levelNumbers.length];
for (int i = 0; i < levelNumbers.length; i++) {
indictmentMinimumLevelNumbers[i] = levelNumbers[i].doubleValue();
}
} else {
for (int i = 0; i < levelNumbers.length; i++) {
double levelNumber = levelNumbers[i].doubleValue();
if (levelNumber < indictmentMinimumLevelNumbers[i]) {
indictmentMinimumLevelNumbers[i] = levelNumber;
}
}
}
}
}
} else {
normalColorFactory = new TangoColorFactory();
}
}
public Color determinePlanningEntityColor(Object planningEntity, Object normalColorObject) {
if (useIndictmentColor) {
Indictment indictment = solutionBusiness.getIndictmentMap().get(planningEntity);
if (indictment != null) {
Number[] levelNumbers = indictment.getScoreTotal().toLevelNumbers();
for (int i = 0; i < levelNumbers.length; i++) {
if (i > INDICTMENT_COLORS.length) {
return TangoColorFactory.ALUMINIUM_3;
}
double levelNumber = levelNumbers[i].doubleValue();
if (levelNumber < 0.0) {
return TangoColorFactory.buildPercentageColor(
INDICTMENT_COLORS[i][0], INDICTMENT_COLORS[i][1],
1.0 - (levelNumber / indictmentMinimumLevelNumbers[i]));
}
}
}
return Color.WHITE;
} else {
return normalColorFactory.pickColor(normalColorObject);
}
}
public String determinePlanningEntityTooltip(Object planningEntity) {
Indictment indictment = solutionBusiness.getIndictmentMap().get(planningEntity);
if (indictment == null) {
return "<html>No indictment</html>";
}
StringBuilder s = new StringBuilder("<html>Indictment: ").append(indictment.getScoreTotal().toShortString());
for (ConstraintMatch constraintMatch : indictment.getConstraintMatchSet()) {
s.append("<br/> ").append(constraintMatch.getConstraintName())
.append(" = ").append(constraintMatch.getScore().toShortString());
}
s.append("</html>");
return s.toString();
}
public void doProblemFactChange(ProblemFactChange<Solution_> problemFactChange) {
doProblemFactChange(problemFactChange, false);
}
public void doProblemFactChange(ProblemFactChange<Solution_> problemFactChange, boolean reset) {
solutionBusiness.doProblemFactChange(problemFactChange);
Solution_ solution = getSolution();
Score score = solutionBusiness.getScore();
if (reset) {
resetPanel(solution);
} else {
updatePanel(solution);
}
validate();
solverAndPersistenceFrame.refreshScoreField(score);
}
}