/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.panels.teststeps;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.impl.wsdl.teststeps.actions.AddAssertionAction;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.testsuite.Assertable;
import com.eviware.soapui.model.testsuite.AssertionError;
import com.eviware.soapui.model.testsuite.AssertionsListener;
import com.eviware.soapui.model.testsuite.TestAssertion;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.action.swing.ActionList;
import com.eviware.soapui.support.action.swing.ActionListBuilder;
import com.eviware.soapui.support.action.swing.ActionSupport;
import com.eviware.soapui.support.components.JXToolBar;
import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Seperate panel for holding/managing assertions
*
* @author ole.matzura
*/
public class AssertionsPanel extends JPanel {
protected AssertionListModel assertionListModel;
protected JList assertionList;
private JPopupMenu assertionListPopup;
private Assertable assertable;
private AddAssertionAction addAssertionAction;
private ConfigureAssertionAction configureAssertionAction;
private RemoveAssertionAction removeAssertionAction;
private MoveAssertionUpAction moveAssertionUpAction;
private MoveAssertionDownAction moveAssertionDownAction;
public AssertionsPanel(Assertable assertable) {
super(new BorderLayout());
this.assertable = assertable;
initListAndModel();
assertionList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
assertionListPopup = new JPopupMenu();
addAssertionAction = new AddAssertionAction(assertable);
assertionListPopup.add(addAssertionAction);
assertionListPopup.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
while (assertionListPopup.getComponentCount() > 1) {
assertionListPopup.remove(1);
}
int ix = assertionList.getSelectedIndex();
if (ix == -1) {
assertionListPopup.addSeparator();
assertionListPopup.add(new ShowOnlineHelpAction(getHelpUrl()));
return;
}
int[] indices = assertionList.getSelectedIndices();
if (indices.length == 1) {
TestAssertion assertion = assertionListModel.getAssertionAt(ix);
ActionSupport.addActions(ActionListBuilder.buildActions(assertion), assertionListPopup);
} else {
TestAssertion[] testAssertion = new TestAssertion[indices.length];
for (int c = 0; c < indices.length; c++) {
testAssertion[c] = assertionListModel.getAssertionAt(indices[c]);
}
ActionSupport.addActions(ActionListBuilder.buildMultiActions(testAssertion), assertionListPopup);
}
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
assertionList.setComponentPopupMenu(assertionListPopup);
assertionList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() < 2) {
return;
}
int ix = assertionList.getSelectedIndex();
if (ix == -1) {
return;
}
Object obj = assertionList.getModel().getElementAt(ix);
if (obj instanceof TestAssertion) {
TestAssertion assertion = (TestAssertion) obj;
if (assertion.isConfigurable()) {
assertion.configure();
}
return;
}
if (obj instanceof AssertionError) {
AssertionError error = (AssertionError) obj;
if (error.getLineNumber() >= 0) {
selectError(error);
} else {
Toolkit.getDefaultToolkit().beep();
}
} else {
Toolkit.getDefaultToolkit().beep();
}
}
});
assertionList.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
int ix = assertionList.getSelectedIndex();
if (ix == -1) {
return;
}
int[] indices = assertionList.getSelectedIndices();
if (indices.length == 1) {
TestAssertion assertion = assertionListModel.getAssertionAt(ix);
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
if (assertion.isConfigurable()) {
assertion.configure();
}
} else {
ActionList actions = ActionListBuilder.buildActions(assertion);
if (actions != null) {
actions.dispatchKeyEvent(e);
}
}
} else {
TestAssertion[] testAssertion = new TestAssertion[indices.length];
for (int c = 0; c < indices.length; c++) {
testAssertion[c] = assertionListModel.getAssertionAt(indices[c]);
}
ActionList actions = ActionListBuilder.buildMultiActions(testAssertion);
ActionSupport.addActions(actions, assertionListPopup);
if (actions != null) {
actions.dispatchKeyEvent(e);
}
}
}
});
add(new JScrollPane(assertionList), BorderLayout.CENTER);
add(buildToolbar(), BorderLayout.NORTH);
}
/**
*
*/
protected void initListAndModel() {
assertionListModel = new AssertionListModel();
assertionList = new JList(assertionListModel);
assertionList.setToolTipText("Assertions for this request");
assertionList.setCellRenderer(new AssertionCellRenderer());
}
private JComponent buildToolbar() {
configureAssertionAction = new ConfigureAssertionAction();
removeAssertionAction = new RemoveAssertionAction();
moveAssertionUpAction = new MoveAssertionUpAction();
moveAssertionDownAction = new MoveAssertionDownAction();
JXToolBar toolbar = UISupport.createToolbar();
addToolbarButtons(toolbar);
toolbar.addGlue();
toolbar.add(new ShowOnlineHelpAction(getHelpUrl()));
assertionList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
int ix = assertionList.getSelectedIndex();
configureAssertionAction.setEnabled(ix >= 0);
removeAssertionAction.setEnabled(ix >= 0);
moveAssertionUpAction.setEnabled(ix >= 0);
moveAssertionDownAction.setEnabled(ix >= 0);
if (ix == -1) {
return;
}
TestAssertion assertion = assertionListModel.getAssertionAt(ix);
configureAssertionAction.setEnabled(assertion != null && assertion.isConfigurable());
}
});
return toolbar;
}
protected void addToolbarButtons(JXToolBar toolbar) {
toolbar.addFixed(UISupport.createToolbarButton(addAssertionAction));
toolbar.addFixed(UISupport.createToolbarButton(configureAssertionAction));
toolbar.addFixed(UISupport.createToolbarButton(removeAssertionAction));
toolbar.addFixed(UISupport.createToolbarButton(moveAssertionUpAction));
toolbar.addFixed(UISupport.createToolbarButton(moveAssertionDownAction));
}
public void setEnabled(boolean enabled) {
assertionList.setEnabled(enabled);
}
protected void selectError(AssertionError error) {
}
private static class AssertionCellRenderer extends JLabel implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
setEnabled(list.isEnabled());
if (value instanceof TestAssertion) {
TestAssertion assertion = (TestAssertion) value;
setText(assertion.getLabel() + " - " + assertion.getStatus().toString());
setIcon(assertion.getIcon());
if (assertion.isDisabled() && isEnabled()) {
setEnabled(false);
}
} else if (value instanceof AssertionError) {
AssertionError assertion = (AssertionError) value;
setText(" -> " + assertion.toString());
setIcon(null);
} else if (value instanceof String) {
setText(value.toString());
}
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setFont(list.getFont());
setOpaque(true);
return this;
}
}
protected class AssertionListModel extends AbstractListModel implements PropertyChangeListener, AssertionsListener {
protected List<Object> items = new ArrayList<Object>();
public AssertionListModel() {
init();
}
public int getSize() {
return items.size();
}
public Object getElementAt(int index) {
return index >= items.size() ? null : items.get(index);
}
public TestAssertion getAssertionAt(int index) {
Object object = items.get(index);
while (!(object instanceof TestAssertion) && index > 0) {
object = items.get(--index);
}
return (TestAssertion) ((object instanceof TestAssertion) ? object : null);
}
public void refresh() {
synchronized (this) {
release();
init();
fireContentsChanged(this, 0, getSize() - 1);
}
}
private void init() {
assertable.addAssertionsListener(this);
for (int c = 0; c < assertable.getAssertionCount(); c++) {
TestAssertion assertion = assertable.getAssertionAt(c);
addAssertion(assertion);
}
}
public void release() {
items.clear();
for (int c = 0; c < assertable.getAssertionCount(); c++) {
TestAssertion assertion = assertable.getAssertionAt(c);
assertion.removePropertyChangeListener(this);
}
assertable.removeAssertionsListener(this);
}
public synchronized void propertyChange(PropertyChangeEvent evt) {
if (SwingUtilities.isEventDispatchThread()) {
refresh();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
refresh();
}
});
}
}
public void assertionAdded(TestAssertion assertion) {
synchronized (this) {
int sz = getSize();
addAssertion(assertion);
fireIntervalAdded(this, sz, items.size() - 1);
}
}
protected void addAssertion(TestAssertion assertion) {
assertion.addPropertyChangeListener(this);
items.add(assertion);
AssertionError[] errors = assertion.getErrors();
if (errors != null) {
for (int i = 0; i < errors.length; i++) {
items.add(errors[i]);
}
}
}
public void assertionRemoved(TestAssertion assertion) {
synchronized (this) {
int ix = items.indexOf(assertion);
if (ix == -1) {
return;
}
assertion.removePropertyChangeListener(this);
items.remove(ix);
fireIntervalRemoved(this, ix, ix);
// remove associated errors
while (ix < items.size() && items.get(ix) instanceof AssertionError) {
items.remove(ix);
fireIntervalRemoved(this, ix, ix);
}
}
}
public void assertionMoved(TestAssertion newAssertion, int ix, int offset) {
synchronized (this) {
// int ix = items.indexOf( assertion );
TestAssertion assertion = (TestAssertion) items.get(ix);
// if first selected can't move up and if last selected can't move
// down
if ((ix == 0 && offset == -1) || (ix == items.size() - 1 && offset == 1)) {
return;
}
assertion.removePropertyChangeListener(this);
items.remove(ix);
fireIntervalRemoved(this, ix, ix);
// remove associated errors
while (ix < items.size() && items.get(ix) instanceof AssertionError) {
items.remove(ix);
fireIntervalRemoved(this, ix, ix);
}
newAssertion.addPropertyChangeListener(this);
items.add(ix + offset, newAssertion);
fireIntervalAdded(this, ix + offset, ix + offset);
// add associated errors
while (ix < items.size() && items.get(ix) instanceof AssertionError) {
items.add(newAssertion);
fireIntervalAdded(this, ix + offset, ix + offset);
}
}
}
}
public void release() {
assertionListModel.release();
addAssertionAction.release();
assertable = null;
}
public class ConfigureAssertionAction extends AbstractAction {
ConfigureAssertionAction() {
super("Configure");
putValue(Action.SHORT_DESCRIPTION, "Configures the selection assertion");
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/preferences.png"));
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
int ix = assertionList.getSelectedIndex();
if (ix == -1) {
return;
}
TestAssertion assertion = assertionListModel.getAssertionAt(ix);
if (assertion.isConfigurable()) {
assertion.configure();
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}
public class RemoveAssertionAction extends AbstractAction {
public RemoveAssertionAction() {
super("Remove Assertion");
putValue(Action.SHORT_DESCRIPTION, "Removes the selected assertion");
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/remove_assertion.gif"));
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
List<TestAssertion> removeAssertionList = new ArrayList<TestAssertion>();
int indices[] = assertionList.getSelectedIndices();
if (indices.length == 0) {
return;
}
if (hasRunningTestCase(indices[0])) {
return;
}
for (int i : indices) {
removeAssertionList.add(assertionListModel.getAssertionAt(i));
}
if (removeAssertionList.size() == 1) {
int selectedIndex = assertionList.getSelectedIndex();
removeSingleAssertion(removeAssertionList.get(0));
if (assertionList.getLastVisibleIndex() >= selectedIndex) {
assertionList.setSelectedIndex(selectedIndex);
}
} else {
removeMultipleAssertions(removeAssertionList);
}
}
private boolean hasRunningTestCase(int assertionIndex) {
if (assertionListModel.getAssertionAt(assertionIndex).getParent().getParent() instanceof TestCase) {
if (SoapUI.getTestMonitor().hasRunningTestCase(
(TestCase) assertionListModel.getAssertionAt(assertionIndex).getParent().getParent())) {
UISupport.showInfoMessage("Can not remove assertion(s) while test case is running");
return true;
}
}
if (assertionListModel.getAssertionAt(assertionIndex).getParent().getParent().getParent() instanceof TestCase) {
if (SoapUI.getTestMonitor().hasRunningSecurityTest(
(TestCase) assertionListModel.getAssertionAt(assertionIndex).getParent().getParent().getParent())) {
UISupport.showInfoMessage("Can not remove assertion(s) while test case is running");
return true;
}
}
return false;
}
private void removeMultipleAssertions(List<TestAssertion> removeAssertionList) {
if (UISupport.confirm("Remove all selected assertions?", "Remove Multiple Assertions")) {
// remove duplicates
Set<TestAssertion> assertions = new HashSet<TestAssertion>();
for (ModelItem target : removeAssertionList) {
assertions.add((TestAssertion) target);
}
for (TestAssertion assertion : assertions) {
((Assertable) assertion.getParent()).removeAssertion(assertion);
}
}
}
private void removeSingleAssertion(TestAssertion assertion) {
if (UISupport.confirm("Remove assertion [" + assertion.getName() + "]", "Remove Assertion")) {
assertable.removeAssertion(assertion);
}
}
}
private class MoveAssertionUpAction extends AbstractAction {
public MoveAssertionUpAction() {
super("Move Assertion Up");
putValue(Action.SHORT_DESCRIPTION, "Moves selected asertion up one row");
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/up_arrow.gif"));
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
int ix = assertionList.getSelectedIndex();
TestAssertion assertion = assertionListModel.getAssertionAt(ix);
if (ix != -1) {
assertion = assertable.moveAssertion(ix, -1);
}
assertionList.setSelectedValue(assertion, true);
}
}
private class MoveAssertionDownAction extends AbstractAction {
public MoveAssertionDownAction() {
super("Move Assertion Down");
putValue(Action.SHORT_DESCRIPTION, "Moves selected asertion down one row");
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/down_arrow.gif"));
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
int ix = assertionList.getSelectedIndex();
TestAssertion assertion = assertionListModel.getAssertionAt(ix);
if (ix != -1) {
assertion = assertable.moveAssertion(ix, 1);
}
assertionList.setSelectedValue(assertion, true);
}
}
public JList getAssertionsList() {
return assertionList;
}
public String getHelpUrl() {
return HelpUrls.RESPONSE_ASSERTIONS_HELP_URL;
}
}