//This file is part of SECONDO. //Copyright (C) 2014, University in Hagen, Department of Computer Science, //Database Systems for New Applications. //SECONDO is free software; you can redistribute it and/or modify //it under the terms of the GNU General Public License as published by //the Free Software Foundation; either version 2 of the License, or //(at your option) any later version. //SECONDO is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. //You should have received a copy of the GNU General Public License //along with SECONDO; if not, write to the Free Software //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package mmdb.gui.query; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; import mmdb.data.MemoryRelation; import mmdb.data.RelationHeaderItem; import mmdb.data.attributes.standard.AttributeInt; import mmdb.gui.QueryDialog; import mmdb.operator.OperationController; import mmdb.operator.OperationController.COperator; import mmdb.query.AbstractQueryController; import mmdb.query.AggregationController; import mmdb.query.ExtensionController; import mmdb.query.JoinController; import mmdb.query.ProjectionController; import mmdb.query.SelectionController; import mmdb.query.UnionController; import mmdb.streamprocessing.parser.Environment; import tools.Reporter; /** * Superclass for all operation panels that are included in the query dialog. * * @author Alexander Castor */ public abstract class AbstractOperationPanel extends JPanel { private static final long serialVersionUID = 5428757906271438415L; /** * The height of the panel's standard component (description, convert, * button). */ private static final int STANDARD_COMPONENT_HEIGHT = 40; /** * The height for the middle area */ protected static final int MIDDLE_HEIGHT = QueryDialog.DIALOG_HEIGHT - 3 * STANDARD_COMPONENT_HEIGHT; /** * The controller which is responsible for executing the query. */ protected AbstractQueryController queryController; /** * The dialog's answer for further processing. ([0] = result relation, [1] = * object name, [2] = convert result to nested list). */ protected Object[] answer; /** * Check box that indicates whether the result relation shall be converted * to a nested list. */ protected JCheckBox convert; /** * The currently available memory relations. */ protected Map relations; /** * Reference to the parent dialog, needed for disposing the window in the * button's action listeners. */ protected JDialog dialog; /** * The previously selected value from the cond attribute list. */ private String previousValueSelection; /** * Creates the UI elements contained in the panel. */ public abstract void constructPanel(); /** * Creates an action listener for the execute button. * * @return the button's action listener */ protected abstract ActionListener createButtonListener(); /** * Adds the description to the top of the panel. * * @param text * the description's text * @param area * the underlying container the components are added to */ protected void addDescriptionPanel(String text, JPanel area) { JPanel descArea = new JPanel(new GridLayout(1, 1)); descArea.setBorder(BorderFactory.createTitledBorder("")); descArea.setPreferredSize(new Dimension(QueryDialog.DIALOG_WIDTH, STANDARD_COMPONENT_HEIGHT)); descArea.setMinimumSize(new Dimension(QueryDialog.DIALOG_WIDTH, STANDARD_COMPONENT_HEIGHT)); descArea.setMaximumSize(new Dimension(2000, STANDARD_COMPONENT_HEIGHT)); JLabel description = new JLabel(text, SwingConstants.CENTER); Font newFont = new Font(description.getFont().getName(), Font.BOLD, description.getFont() .getSize()); description.setFont(newFont); description.setForeground(Color.WHITE); descArea.setBackground(Color.GRAY); descArea.add(description); area.add(descArea); } /** * Adds the convert to list panel to the bottom of the panel. * * @param area * the underlying container the components are added to */ protected void addConvertToListPanel(JPanel area) { JPanel convertArea = new JPanel(new FlowLayout()); JLabel text = new JLabel("CONVERT RESULT RELATION AUTOMATICALLY TO NESTED LIST?"); convert = new JCheckBox(); convert.setSelected(false); convertArea.setPreferredSize(new Dimension(QueryDialog.DIALOG_WIDTH, STANDARD_COMPONENT_HEIGHT)); convertArea.setMinimumSize(new Dimension(QueryDialog.DIALOG_WIDTH, STANDARD_COMPONENT_HEIGHT)); convertArea.setMaximumSize(new Dimension(2000, STANDARD_COMPONENT_HEIGHT)); Font newFont = new Font(text.getFont().getName(), Font.BOLD + Font.ITALIC, 12); text.setFont(newFont); text.setForeground(Color.GRAY); convertArea.setAlignmentX(CENTER_ALIGNMENT); convertArea.setAlignmentY(CENTER_ALIGNMENT); convertArea.add(text); convertArea.add(convert); area.add(convertArea); } /** * Adds the button to the bottom of the panel. * * @param area * the underlying container the components are added to */ protected void addButtonPanel(JPanel area) { JPanel buttonArea = new JPanel(new GridLayout(1, 1)); JButton button = new JButton("EXECUTE"); buttonArea.setPreferredSize(new Dimension(QueryDialog.DIALOG_WIDTH, STANDARD_COMPONENT_HEIGHT)); buttonArea .setMinimumSize(new Dimension(QueryDialog.DIALOG_WIDTH, STANDARD_COMPONENT_HEIGHT)); buttonArea.setMaximumSize(new Dimension(2000, STANDARD_COMPONENT_HEIGHT)); button.addActionListener(createButtonListener()); button.setOpaque(true); Font newFont = new Font(button.getFont().getName(), Font.BOLD, 18); button.setFont(newFont); button.setBackground(Color.GRAY); buttonArea.add(button); area.add(buttonArea); } /** * Dynamically fills an attribute list for a conditional operator depending * on the user's relation and operator selection. * * @param selectedRelation * the selected relation * @param operator * the selected operator * @param attributeList * the list to which the relation's attributes shall be added */ protected void fillCondAttributeList(String selectedRelation, COperator operator, JComboBox attributeList) { if (attributeList.getSelectedItem() != null) { previousValueSelection = (String) attributeList.getSelectedItem(); } DefaultComboBoxModel model = (DefaultComboBoxModel) attributeList.getModel(); model.removeAllElements(); if (selectedRelation == null || operator == null) { return; } MemoryRelation relation = relations.get(selectedRelation); List> argumentClasses = OperationController.getCondAttributeClasses(operator); List insertedElements = new ArrayList(); for (RelationHeaderItem item : relation.getHeader()) { if (!item.isProjected()) { continue; } for (Class argumentClass : argumentClasses) { if (argumentClass.isAssignableFrom(item.getType())) { String element = item.getIdentifier() + " (" + item.getTypeName() + ")"; if (!insertedElements.contains(element)) { model.addElement(element); insertedElements.add(element); } } } } int previousIndex = model.getIndexOf(previousValueSelection); if (!insertedElements.isEmpty()) { if (previousIndex > 0) { attributeList.setSelectedIndex(previousIndex); } else { attributeList.setSelectedIndex(0); } } } /** * Creates the object name for the result relation to be displayed in the * object explorer. * * @param operationName * the operation's name * @param selectedRelation * the first relation's name * @return the object name for the result relation */ protected String createObjectName(String operationName, String selectedRelation) { int indexOfBrackets = selectedRelation.indexOf("[+"); String relationName; if (selectedRelation.contains(";")) { relationName = selectedRelation.substring(0, indexOfBrackets - 2); } else { relationName = selectedRelation.substring(0, indexOfBrackets - 1); } return Environment.nextResultLabel() + operationName + " ON " + Environment.removeResultLabel(relationName); } /** * Creates the object name for the result relation to be displayed in the * object explorer. * * @param operationName * the operation's name * @param selectedFirstRelation * the first relation's name * @param selectedSecondRelation * the second relation's name * @return the object name for the result relation */ protected String createObjectName(String operationName, String selectedFirstRelation, String selectedSecondRelation) { int indexOfBracketsForFirstRelation = selectedFirstRelation.indexOf("["); int indexOfBracketsForSecondRelation = selectedSecondRelation.indexOf("["); String firstRelationName; if (selectedFirstRelation.contains(";")) { firstRelationName = selectedFirstRelation.substring(0, indexOfBracketsForFirstRelation - 2); } else { firstRelationName = selectedFirstRelation.substring(0, indexOfBracketsForFirstRelation - 1); } String secondRelationName; if (selectedSecondRelation.contains(";")) { secondRelationName = selectedSecondRelation.substring(0, indexOfBracketsForSecondRelation - 2); } else { secondRelationName = selectedSecondRelation.substring(0, indexOfBracketsForSecondRelation - 1); } return Environment.nextResultLabel() + Environment.removeResultLabel(firstRelationName) + " " + operationName + " " + Environment.removeResultLabel(secondRelationName); } /** * Removes the type name from the attribute name. * * @param attribute * the attribute which is selected * @return string containing only the identifier */ protected String removeType(String attribute) { return attribute.substring(0, attribute.indexOf("(") - 1); } /** * Removes the identifier from the attribute name. * * @param attribute * the attribute which is selected * @return string containing only the type */ protected String removeIdentifier(String attribute) { return attribute.substring(attribute.indexOf("(") + 1, attribute.length() - 1); } /** * Removes all type names from the attribute list. * * @param attributeList * the attribute list which is selected * @return an attribute list containing only the identifiers */ protected List removeTypes(List attributeList) { List cleanAttributeList = new ArrayList(); for (String attribute : attributeList) { cleanAttributeList.add(removeType(attribute)); } return cleanAttributeList; } /** * Displays the info box in case of queries in measure mode. * * @param resultRelation * the relation containing the number of result tuples * @param duration * the duration of the query execution */ protected void showMeasureModeInfoBox(MemoryRelation resultRelation, long duration) { AttributeInt resultAttribute = (AttributeInt) resultRelation.getTuples().get(0) .getAttribute(0); int tuplesCount = resultAttribute.getValue(); Reporter.showInfo("RESULT OF QUERY ...\n\n" + "> duration: " + duration + " [ms]\n" + "> tuples: " + tuplesCount); } /** * Method for injecting member references. * * @param answer * the dialog's answer * @param relations * the available relations */ public void injectMembers(Object[] answer, Map relations, JDialog dialog, AbstractQueryController controller) { this.answer = answer; this.relations = relations; this.dialog = dialog; this.queryController = controller; } /** * Enum for collecting all query panels. */ public static enum QueryPanel { SELECTION(1, SelectionPanel.class, SelectionController.class), PROJECTION(2, ProjectionPanel.class, ProjectionController.class), EXTENSION(3, ExtensionPanel.class, ExtensionController.class), UNION(4, UnionPanel.class, UnionController.class), JOIN(5, JoinPanel.class, JoinController.class), AGGREGATION( 6, AggregationPanel.class, AggregationController.class); QueryPanel(int position, Class panelClass, Class controllerClass) { this.position = position; this.panelClass = panelClass; this.controllerClass = controllerClass; } public final int position; public final Class panelClass; public final Class controllerClass; } }