blob: 9d8d76d56b5d611844a93d78390822d6ad88a219 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 com.google.gct.testing;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.gct.testing.ui.AddCompareScreenshotPanel;
import com.google.gct.testing.ui.AddScreenshotListener;
import com.google.gct.testing.ui.WipePanel;
import com.google.gct.testing.ui.WipePanelCallback;
import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.impl.ActionButton;
import com.intellij.openapi.actionSystem.impl.PresentationFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
public class ScreenshotComparisonDialog {
private final Set<ScreenshotComparisonHeaderPanelListener> headerListeners = new HashSet<ScreenshotComparisonHeaderPanelListener>();
private final Project myProject;
private final AbstractTestProxy testTreeRoot;
private final CloudTestConfigurationImpl configuration;
private final ConfigurationInstance configurationInstance;
@Nullable private final ConfigurationInstance anotherConfigurationInstance;
private final List<TestName> allTests;
private TestName currentTest;
private final Map<String, ConfigurationResult> results;
private int step = 1;
private int maxStep = 1;
private final List<ScreenshotComparisonPanel> screenshotPanels = new LinkedList<ScreenshotComparisonPanel>();
private final Map<TestName, Integer> testToStep = new HashMap<TestName, Integer>();
private JPanel myPanel;
private JPanel myHeaderPanel;
private JPanel myAllScreenshotsPanel;
private JPanel myLeftHeaderPanel;
private JPanel myRightHeaderPanel;
private JPanel myScreenshotNamePanel;
private JLabel myScreenshotNameLabel;
private Window myWindow;
private JComboBox myTestComboBox;
private JLabel myStepLabel;
private AddCompareScreenshotPanel addScreenshotPanel;
private ActionButton myDecrementStepButton;
private ActionButton myIncrementStepButton;
private Function<ConfigurationResult,String> getName;
public ScreenshotComparisonDialog(Project project,
AbstractTestProxy testTreeRoot,
CloudTestConfigurationImpl configuration,
ConfigurationInstance configurationInstance,
@Nullable ConfigurationInstance anotherConfigurationInstance,
List<TestName> allTests,
TestName currentTest,
Map<String, ConfigurationResult> results) {
myProject = project;
this.testTreeRoot = testTreeRoot;
this.configuration = configuration;
this.configurationInstance = configurationInstance;
this.anotherConfigurationInstance = anotherConfigurationInstance;
this.allTests = allTests;
this.currentTest = currentTest;
this.results = results;
for (TestName test : allTests) {
testToStep.put(test, 1);
}
}
public void showDialog() {
DialogBuilder builder = new DialogBuilder(myProject);
builder.setCenterPanel(myPanel);
builder.setPreferredFocusComponent(myLeftHeaderPanel);
builder.setTitle("Screenshot Viewer");
builder.removeAllActions();
populateHeaderPanel();
createFirstScreenshotComparisonPanel(configurationInstance);
addScreenshotPanel = new AddCompareScreenshotPanel();
//addScreenshotPanel.setHeight(UIUtil.isUnderDarcula() ? 585 : 570);
addScreenshotPanel.addListener(new AddScreenshotListener() {
@Override
public void addScreenshot() {
addScreenshotComparisonPanel(screenshotPanels.get(screenshotPanels.size() - 1));
}
});
myAllScreenshotsPanel.add(addScreenshotPanel.getPanel());
myTestComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
TestName selectedTest = (TestName)myTestComboBox.getSelectedItem();
if (!selectedTest.equals(currentTest)) {
testToStep.put(currentTest, step);
currentTest = selectedTest;
step = testToStep.get(currentTest);
notifyHeaderListenersAboutStep(false);
}
for (ScreenshotComparisonHeaderPanelListener headerListener : headerListeners) {
headerListener.updateTest(selectedTest, true);
}
updateMaxStep();
}
});
myTestComboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof TestName) {
final TestName testName = (TestName)value;
label.setText(testName.getDisplayName());
}
return label;
}
});
myWindow = builder.getWindow();
updateMaxStep();
updateScreenshotName();
builder.show();
}
public Window getWindow() {
return myWindow;
}
private void createFirstScreenshotComparisonPanel(ConfigurationInstance configurationInstance) {
ScreenshotComparisonPanel screenshotComparisonPanel =
new ScreenshotComparisonPanel(this, null, testTreeRoot, configuration, configurationInstance,
(TestName)myTestComboBox.getSelectedItem(), step, results);
screenshotPanels.add(screenshotComparisonPanel);
WipePanel wipePanel = screenshotComparisonPanel.getPanel();
myAllScreenshotsPanel.add(wipePanel);
wipePanel.instantReveal(new WipePanelCallback() {
@Override
public void panelRevealed() {
fitWindow();
}
});
headerListeners.add(screenshotComparisonPanel);
}
private void populateHeaderPanel() {
//myLeftHeaderPanel.add(new JLabel("Test:"));
myTestComboBox = new JComboBox();
myTestComboBox.setModel(new DefaultComboBoxModel(new Vector(allTests)));
myTestComboBox.setSelectedItem(currentTest);
myLeftHeaderPanel.add(myTestComboBox);
myScreenshotNameLabel = new JLabel("");
myScreenshotNameLabel.setFont(myScreenshotNameLabel.getFont().deriveFont(Font.BOLD).deriveFont(18.0f));
myScreenshotNamePanel.add(myScreenshotNameLabel);
myScreenshotNamePanel.setBorder(new EmptyBorder(0, 15, 0, 0));
AnAction decrementStepAction = new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
step--;
// This is not expected to happen, but just in case.
if (step < 1) {
step = 1;
}
updateStepLabel();
notifyHeaderListenersAboutStep(true);
}
@Override
public void update(AnActionEvent event) {
Presentation presentation = event.getPresentation();
presentation.setIcon(AllIcons.Actions.Back);
}
};
PresentationFactory presentationFactory = new PresentationFactory();
myDecrementStepButton =
new ActionButton(decrementStepAction, presentationFactory.getPresentation(decrementStepAction), "MyPlace", new Dimension(25, 25));
myRightHeaderPanel.add(myDecrementStepButton);
myStepLabel = new JLabel();
myRightHeaderPanel.add(myStepLabel);
AnAction incrementStepAction = new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
step++;
// This is not expected to happen, but just in case.
if (step > maxStep) {
step = maxStep;
}
updateStepLabel();
notifyHeaderListenersAboutStep(true);
}
@Override
public void update(AnActionEvent event) {
Presentation presentation = event.getPresentation();
presentation.setIcon(AllIcons.Actions.Forward);
}
};
myIncrementStepButton =
new ActionButton(incrementStepAction, presentationFactory.getPresentation(incrementStepAction), "MyPlace", new Dimension(25, 25));
myRightHeaderPanel.add(myIncrementStepButton);
updateStepLabel();
}
private void notifyHeaderListenersAboutStep(boolean shouldUpdateImage) {
updateScreenshotName();
for (ScreenshotComparisonHeaderPanelListener headerListener : headerListeners) {
headerListener.updateStep(step, shouldUpdateImage);
}
}
private void updateScreenshotName() {
myScreenshotNameLabel.setText("Screenshot name");
for (ConfigurationResult result : results.values()) {
String screenshotName = result.getScreenshotNameForTestAndStep(currentTest, step);
if (!screenshotName.isEmpty()) {
myScreenshotNameLabel.setText(screenshotName);
break;
}
}
}
private void updateStepLabel() {
myStepLabel.setText("Screenshot " + step + "/" + maxStep);
myDecrementStepButton.setEnabled(step > 1);
myIncrementStepButton.setEnabled(step < maxStep);
}
public void addScreenshotComparisonPanel(ScreenshotComparisonPanel createAfterPanel) {
int index = 0;
for (Component component : myAllScreenshotsPanel.getComponents()) {
if (component == createAfterPanel.getPanel()) {
ScreenshotComparisonPanel screenshotComparisonPanel =
new ScreenshotComparisonPanel(this, createAfterPanel, testTreeRoot, configuration,
createAfterPanel.computeSelectedConfigurationInstance(), (TestName)myTestComboBox.getSelectedItem(),
step, results);
screenshotPanels.add(index + 1, screenshotComparisonPanel);
updateMaxStep();
WipePanel newPanel = screenshotComparisonPanel.getPanel();
myAllScreenshotsPanel.add(newPanel, index + 1);
headerListeners.add(screenshotComparisonPanel);
fitWindow();
newPanel.reveal(null);
return;
}
index++;
}
throw new IllegalArgumentException("Could not find panel to insert after: " + createAfterPanel);
}
public void fitWindow() {
if (myWindow == null) {
return;
}
myAllScreenshotsPanel.updateUI();
myWindow.pack();
int maxHeight = 0;
for (ScreenshotComparisonPanel panel : screenshotPanels) {
if (panel.getPanel().getHeight() > maxHeight) {
maxHeight = panel.getPanel().getHeight();
}
}
addScreenshotPanel.setHeight(maxHeight);
myAllScreenshotsPanel.updateUI();
myWindow.pack();
}
public void removeScreenshotComparisonPanel(final ScreenshotComparisonPanel removedPanel) {
WipePanel panel = removedPanel.getPanel();
panel.unReveal(new WipePanelCallback() {
@Override
public void panelHidden(WipePanel panel) {
headerListeners.remove(removedPanel);
screenshotPanels.remove(removedPanel);
removedPanel.stopListeningToResults();
myAllScreenshotsPanel.remove(panel);
if (myAllScreenshotsPanel.getComponentCount() == 1) {
myWindow.dispose();
} else {
updateMaxStep();
fitWindow();
}
}
});
}
void updateMaxStep() {
maxStep = Ordering.natural().max(Iterables.transform(screenshotPanels, new Function<ScreenshotComparisonPanel, Integer>() {
@Override
public Integer apply(ScreenshotComparisonPanel panel) {
return panel.getMaxStep();
}
}));
int oldStep = step;
step = Math.min(step, maxStep);
// In case we got new screenshots.
if (step == 0 && maxStep != 0) {
step = 1;
}
updateStepLabel();
if (step != oldStep) {
notifyHeaderListenersAboutStep(true);
}
}
}