package gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import controller.QueryRowController;
import util.AnnotationDataType;
import util.IconFactory;
/**
* Class the represents a row in the query builder
*
* @author bDtKarlsson
*/
public class QueryBuilderRow extends JPanel {
private static final long serialVersionUID = -7684513985741278158L;
private JComboBox annotationBox;
private JComboBox annotationAlternatives;
private JTextField textField;
private JButton plusButton;
private JButton minusButton;
private JComboBox logicBox;
private QuerySearchTab parent;
private CopyOnWriteArrayList<AnnotationDataType> annotationTypes;
private static final String[] logicOperators = { "AND", "NOT", "OR" };
private boolean dropdown = false;
private boolean firstRow = false;
private boolean lastRow = false;
private QueryRowController queryRowController;
public QueryBuilderRow(QuerySearchTab parent,
AnnotationDataType[] annotationTypes,
QueryRowController queryRowController) {
/* The Parent query search tab */
this.parent = parent;
/* The annotation information */
this.annotationTypes = new CopyOnWriteArrayList<>();
this.queryRowController = queryRowController;
setLayout(new FlowLayout());
/* Set up the components (fieldBox must be set last) */
setPlusButton();
setMinusButton();
setLogicBox();
setTextField();
setAnnotationAlternatives(new String[0]);
setAnnotationBox(annotationTypes);
}
/**
* Method for setting information about the row
*
* @param firstRow
* - if the row is the first row
* @param lastRow
* - if the row is the last row
*/
public synchronized void setAs(Boolean firstRow, Boolean lastRow) {
this.firstRow = firstRow;
this.lastRow = lastRow;
/* Remove all current components */
removeAll();
/* Create the panels */
JPanel logicPanel = new JPanel(new BorderLayout());
logicPanel.setPreferredSize(new Dimension(70, 30));
JPanel annotationPanel = new JPanel(new BorderLayout());
annotationPanel.setPreferredSize(new Dimension(240, 30));
JPanel inputPanel = new JPanel(new BorderLayout());
inputPanel.setPreferredSize(new Dimension(450, 30));
JPanel firstButtonPanel = new JPanel();
firstButtonPanel.setPreferredSize(new Dimension(25, 30));
JPanel secondButtonPanel = new JPanel();
secondButtonPanel.setPreferredSize(new Dimension(25, 30));
/* All rows except the first should have a logic field */
if (!firstRow) {
logicPanel.add(logicBox, BorderLayout.CENTER);
}
/* All rows should have a annotation field */
if (annotationBox == null) {
annotationBox = new JComboBox();
}
annotationPanel.add(annotationBox, BorderLayout.CENTER);
/*
* If the selected annotation has predefinied values the row should have
* a dropdown menu with annotation alternatives, else it should have a
* text field for free text input
*/
if (dropdown) {
inputPanel.add(annotationAlternatives, BorderLayout.CENTER);
} else {
inputPanel.add(textField, BorderLayout.CENTER);
}
/*
* All rows except if there is only one row in the builder should have a
* minus button
*/
if (!(firstRow && lastRow)) {
firstButtonPanel.add(minusButton);
}
/* The last row shoyld have a plus button */
if (lastRow) {
if (firstRow) {
firstButtonPanel.add(plusButton);
} else {
secondButtonPanel.add(plusButton);
}
}
add(logicPanel);
add(Box.createHorizontalStrut(5));
add(annotationPanel);
add(Box.createHorizontalStrut(5));
add(inputPanel);
add(firstButtonPanel);
add(secondButtonPanel);
}
/**
* Method for constructing the plus button
*/
private void setPlusButton() {
plusButton = CustomButtonFactory.makeCustomButton(
IconFactory.getPlusIcon(15, 15),
IconFactory.getPlusIcon(17, 17), 17, 25, null);
plusButton.addActionListener(queryRowController
.createPlusButtonListener());
plusButton.setFocusable(false);
}
/**
* Method for constructing a minus button
*/
private void setMinusButton() {
minusButton = CustomButtonFactory.makeCustomButton(
IconFactory.getMinusIcon(15, 15),
IconFactory.getMinusIcon(17, 17), 17, 25, null);
minusButton.addActionListener(queryRowController
.createMinusButtonListener(this));
minusButton.setFocusable(false);
}
/**
* Method for constructing the text field for free text input
*/
private void setTextField() {
textField = new JTextField();
/*
* The search field in the parent is updated when the text field content
* is changed
*/
textField.getDocument().addDocumentListener(
queryRowController.createDocumentListener());
setTextFieldOnEnterListener(textField);
}
private void focusNextQuery() {
parent.getNextQuery(this).getTextField().requestFocus();
}
public JTextField getTextField() {
return this.textField;
}
private void onPressedEnter() {
parent.getSearchButton().doClick();
}
private void setTextFieldOnEnterListener(JTextField textField) {
final QueryBuilderRow queryRow = this;
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent event) {
if (event.getKeyCode() == event.VK_ENTER) {
if (parent.isLastQueryIndex(queryRow)) {
onPressedEnter();
} else {
focusNextQuery();
}
}
}
});
}
/**
* Method for constructing the annotation alternatives combobox
*
* @param alternatives
* - the annotation alternatives
*/
private void setAnnotationAlternatives(String[] alternatives) {
annotationAlternatives = new JComboBox(alternatives);
annotationAlternatives.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
/* Update search area in parent when selected item is changed */
parent.updateSearchArea();
}
});
}
private CopyOnWriteArrayList<AnnotationDataType> getManuallyAddedAnnotations() {
CopyOnWriteArrayList<AnnotationDataType> annotations = new CopyOnWriteArrayList<>();
annotations.add(new AnnotationDataType("ExpID", null, true));
annotations.add(new AnnotationDataType("FileName", null, true));
annotations.add(new AnnotationDataType("FileType", new String[] {
"Raw", "Profile", "Region" }, true));
annotations.add(new AnnotationDataType("Date", null, true));
annotations.add(new AnnotationDataType("Author", null, true));
annotations.add(new AnnotationDataType("Uploader", null, true));
return annotations;
}
/**
* Method for creating the annotations combobox
*
* @param annotations
* - the annotations
*/
public void setAnnotationBox(AnnotationDataType[] annotations) {
annotationTypes = new CopyOnWriteArrayList<>();
annotationTypes.addAll(getManuallyAddedAnnotations());
annotationTypes.addAll(new ArrayList<>(Arrays.asList(annotations)));
/* Get the annotation names */
final ArrayList<String> annotationNames = new ArrayList<>();
for (AnnotationDataType dataType : annotationTypes) {
annotationNames.add(dataType.getName());
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (annotationNames.size() > 0) {
annotationBox = new JComboBox<String>(annotationNames
.toArray(new String[annotationNames.size()])); // TODO Denna rad kastar exception ibland vid uppstart.
} else {
annotationBox = new JComboBox<String>();
}
annotationBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
/*
* When the selected item in the box is changed a check
* must be made to know wether a free text field or a
* annotation alternatives box should be displayed
*/
String annotation = (String) annotationBox
.getSelectedItem();
dropdown = false;
for (AnnotationDataType dataType : annotationTypes) {
if (annotation.equals(dataType.getName())) {
String[] values = dataType.getValues();
if (values != null) {
if (!values[0].equals("freetext") || values.length>1) {
/* Dropdown annotation alternatives box */
dropdown = true;
setAnnotationAlternatives(values);
} else {
/* Free text field */
dropdown = false;
}
}
}
/* Update row and parent search area */
setAs(firstRow, lastRow);
parent.updateSearchArea();
repaint();
revalidate();
}
}
});
/*
* Change selected item so the actionlistener will be called
* upon starting the program
*/
if (annotationBox.getSelectedIndex() != -1) {
annotationBox.setSelectedIndex(0);
}
}
});
}
/**
* Method for creating the logic box
*/
private void setLogicBox() {
logicBox = new JComboBox<Object>(logicOperators);
logicBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
/*
* Update the parent search area when selected logic operator is
* changed
*/
parent.updateSearchArea();
}
});
}
/**
* Get text either from the freetext field or the annotation alternatives
* box
*
* @return
*/
public String getText() {
if (!dropdown) {
return textField.getText();
} else {
return (String) annotationAlternatives.getSelectedItem();
}
}
/**
* Get the selected logic operator
*
* @return logic operator
*/
public String getLogic() {
return (String) logicBox.getSelectedItem();
}
/**
* Get the selected annotation
*
* @return the annotation
*/
public String getAnnotation() {
return (String) annotationBox.getSelectedItem();
}
public void setEnabled(boolean enabled) {
annotationBox.setEnabled(enabled);
annotationAlternatives.setEnabled(enabled);
logicBox.setEnabled(enabled);
textField.setEnabled(enabled);
plusButton.setEnabled(enabled);
minusButton.setEnabled(enabled);
}
}