Files
secondo/Javagui/mmdb/gui/query/AbstractOperationPanel.java

398 lines
13 KiB
Java
Raw Permalink Normal View History

2026-01-23 17:03:45 +08:00
//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<String, MemoryRelation> 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<Class<?>> argumentClasses = OperationController.getCondAttributeClasses(operator);
List<String> insertedElements = new ArrayList<String>();
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<String> removeTypes(List<String> attributeList) {
List<String> cleanAttributeList = new ArrayList<String>();
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<String, MemoryRelation> 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<? extends AbstractOperationPanel> panelClass,
Class<? extends AbstractQueryController> controllerClass) {
this.position = position;
this.panelClass = panelClass;
this.controllerClass = controllerClass;
}
public final int position;
public final Class<? extends AbstractOperationPanel> panelClass;
public final Class<? extends AbstractQueryController> controllerClass;
}
}