Merge branch 'master' of git@github.com:jOOQ/jOOQ.git

This commit is contained in:
Lukas Eder 2012-07-01 10:29:17 +02:00
commit f8527b3dbb
9 changed files with 354 additions and 69 deletions

View File

@ -48,6 +48,7 @@ public class BreakpointHit implements Serializable {
STEP_THROUGH,
RUN_OVER,
RUN,
FAIL,
}
private boolean isBeforeExecution;

View File

@ -47,6 +47,7 @@ import java.util.List;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteType;
import org.jooq.debug.BreakpointHit.ExecutionType;
import org.jooq.exception.DataAccessException;
import org.jooq.impl.DefaultExecuteListener;
import org.jooq.impl.Factory;
@ -241,6 +242,9 @@ public class DebugListener extends DefaultExecuteListener {
matchingDebugger = null;
}
switch(executionType) {
case FAIL: {
throw new DataAccessException("Failing SQL statement.");
}
case RUN_OVER: {
try {
ctx.statement().close();

View File

@ -81,30 +81,32 @@ public class LocalStatementExecutor implements StatementExecutor {
boolean isAllowed = true;
if(executorContext.isReadOnly()) {
String simplifiedSql = sql.replaceAll("'[^']*'", "");
Matcher matcher = Pattern.compile("[a-zA-Z_0-9\\$]+").matcher(simplifiedSql);
boolean isFirst = true;
while(matcher.find()) {
String word = simplifiedSql.substring(matcher.start(), matcher.end()).toUpperCase(Locale.ENGLISH);
if(isFirst && !word.equals("SELECT")) {
switch(SqlQueryType.detectType(simplifiedSql)) {
case SELECT:
String[] forbiddenWords = new String[] {
"INSERT",
"UPDATE",
"DELETE",
"ALTER",
"DROP",
"CREATE",
"EXEC",
"EXECUTE",
};
Matcher matcher = Pattern.compile("[a-zA-Z_0-9\\$]+").matcher(simplifiedSql);
while(matcher.find()) {
String word = simplifiedSql.substring(matcher.start(), matcher.end()).toUpperCase(Locale.ENGLISH);
for(String keyword: forbiddenWords) {
if(word.equals(keyword)) {
isAllowed = false;
break;
}
}
}
break;
default:
isAllowed = false;
break;
}
isFirst = false;
for(String keyword: new String[] {
"INSERT",
"UPDATE",
"DELETE",
"ALTER",
"DROP",
"CREATE",
"EXEC",
"EXECUTE",
}) {
if(word.equals(keyword)) {
isAllowed = false;
break;
}
}
}
}
if(!isAllowed) {

View File

@ -52,13 +52,11 @@ import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import org.jooq.debug.Breakpoint;
import org.jooq.debug.SqlQueryType;
@ -92,9 +90,7 @@ public class BreakpointEditor extends JPanel {
private JPanel processorPane;
private JCheckBox beforeExecutionCheckBox;
private StatementProcessorPane beforeExecutionProcessorPane;
private JRadioButton executeRadioButton;
// private JRadioButton doNotExecuteRadioButton;
private JRadioButton replaceExecutionRadioButton;
private JComboBox executeTypeComboBox;
private StatementProcessorPane replacementExecutionProcessorPane;
private JCheckBox afterExecutionCheckBox;
private StatementProcessorPane afterExecutionProcessorPane;
@ -228,35 +224,21 @@ public class BreakpointEditor extends JPanel {
beforeExecutionProcessorPane = new StatementProcessorPane(beforeExecutionProcessor);
processorPane.add(beforeExecutionProcessorPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(2, 5, 0, 0), 0, 0));
y++;
ButtonGroup executionButtonGroup = new ButtonGroup();
StatementProcessor replacementExecutionProcessor = breakpoint.getReplacementExecutionProcessor();
executeRadioButton = new JRadioButton("Execute");
executeRadioButton.setOpaque(false);
executionButtonGroup.add(executeRadioButton);
processorPane.add(executeRadioButton, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
y++;
executeTypeComboBox = new JComboBox(new String[] {"Execute", "Replace with"});
// doNotExecuteRadioButton = new JRadioButton("Do not execute");
// executionButtonGroup.add(doNotExecuteRadioButton);
// processorPane.add(doNotExecuteRadioButton, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
// y++;
replaceExecutionRadioButton = new JRadioButton("Replace with: ");
replaceExecutionRadioButton.setOpaque(false);
executionButtonGroup.add(replaceExecutionRadioButton);
if(replacementExecutionProcessor != null) {
replaceExecutionRadioButton.setSelected(true);
executeTypeComboBox.setSelectedIndex(1);
} else {
executeRadioButton.setSelected(true);
executeTypeComboBox.setSelectedIndex(0);
}
processorPane.add(replaceExecutionRadioButton, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
processorPane.add(executeTypeComboBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
replacementExecutionProcessorPane = new StatementProcessorPane(breakpoint.getReplacementExecutionProcessor());
processorPane.add(replacementExecutionProcessorPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
executeRadioButton.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
adjustStates();
}
});
replaceExecutionRadioButton.addItemListener(new ItemListener() {
executeTypeComboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
adjustStates();
@ -296,10 +278,9 @@ public class BreakpointEditor extends JPanel {
processorPane.setVisible(isActive && breakpointTypeComboBox.getSelectedItem() == PROCESS);
beforeExecutionCheckBox.setEnabled(isActive);
beforeExecutionProcessorPane.setLocked(!isActive || !beforeExecutionCheckBox.isSelected());
executeRadioButton.setEnabled(isActive);
replaceExecutionRadioButton.setEnabled(isActive);
executeTypeComboBox.setEnabled(isActive);
// doNotExecuteRadioButton;
replacementExecutionProcessorPane.setLocked(!isActive || !replaceExecutionRadioButton.isSelected());
replacementExecutionProcessorPane.setLocked(!isActive || executeTypeComboBox.getSelectedIndex() != 1);
afterExecutionCheckBox.setEnabled(isActive);
afterExecutionProcessorPane.setLocked(!isActive || !afterExecutionCheckBox.isSelected());
}
@ -345,7 +326,7 @@ public class BreakpointEditor extends JPanel {
StatementProcessor afterExecutionProcessor = null;
if(!isBreaking) {
beforeExecutionProcessor = beforeExecutionCheckBox.isSelected()? beforeExecutionProcessorPane.getStatementProcessor(): null;
replacementExecutionProcessor = replaceExecutionRadioButton.isSelected()? replacementExecutionProcessorPane.getStatementProcessor(): null;
replacementExecutionProcessor = executeTypeComboBox.getSelectedIndex() == 1? replacementExecutionProcessorPane.getStatementProcessor(): null;
afterExecutionProcessor = afterExecutionCheckBox.isSelected()? afterExecutionProcessorPane.getStatementProcessor(): null;
}
return new Breakpoint(id, hitCount, statementMatcher, isBreaking, beforeExecutionProcessor, replacementExecutionProcessor, afterExecutionProcessor);

View File

@ -120,10 +120,18 @@ public class BreakpointHitEditor extends JPanel {
executeTypeNoneRadioButton.setSelected(true);
executionTypeGroup.add(executeTypeNoneRadioButton);
executionTypePane.add(executeTypeNoneRadioButton);
JRadioButton executeTypeBreakRadioButton = new JRadioButton("Execute and break");
final JRadioButton executeTypeBreakRadioButton = new JRadioButton("Execute and break");
executeTypeBreakRadioButton.setOpaque(false);
executionTypeGroup.add(executeTypeBreakRadioButton);
executionTypePane.add(executeTypeBreakRadioButton);
final JRadioButton executeTypeSkipRadioButton = new JRadioButton("Skip");
executeTypeSkipRadioButton.setOpaque(false);
executionTypeGroup.add(executeTypeSkipRadioButton);
executionTypePane.add(executeTypeSkipRadioButton);
final JRadioButton executeTypeFailRadioButton = new JRadioButton("Throw exception");
executeTypeFailRadioButton.setOpaque(false);
executionTypeGroup.add(executeTypeFailRadioButton);
executionTypePane.add(executeTypeFailRadioButton);
breakpointHitExecutionPane.add(executionTypePane, new GridBagConstraints(0, y++, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
buttonPane.setOpaque(false);
@ -134,7 +142,20 @@ public class BreakpointHitEditor extends JPanel {
@Override
public void actionPerformed(ActionEvent e) {
if(breakpointHit.isBeforeExecution()) {
breakpointHit.setExecutionType(executeTypeNoneRadioButton.isSelected()? ExecutionType.RUN: ExecutionType.STEP_THROUGH, replaceStatementCheckBox.isSelected()? replacementSQLTextArea.getText(): null);
String replacementSQL = null;
ExecutionType executionType = ExecutionType.RUN;
if(executeTypeNoneRadioButton.isSelected()) {
executionType = ExecutionType.RUN;
replacementSQL = replaceStatementCheckBox.isSelected()? replacementSQLTextArea.getText(): null;
} else if(executeTypeBreakRadioButton.isSelected()) {
executionType = ExecutionType.STEP_THROUGH;
replacementSQL = replaceStatementCheckBox.isSelected()? replacementSQLTextArea.getText(): null;
} else if(executeTypeSkipRadioButton.isSelected()) {
executionType = ExecutionType.RUN_OVER;
} else if(executeTypeFailRadioButton.isSelected()) {
executionType = ExecutionType.FAIL;
}
breakpointHit.setExecutionType(executionType, replacementSQL);
} else {
breakpointHit.setExecutionType(ExecutionType.RUN, null);
}

View File

@ -66,13 +66,16 @@ import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.jooq.debug.Debugger;
import org.jooq.debug.DebuggerRegistry;
import org.jooq.debug.LocalDebugger;
import org.jooq.debug.console.misc.JSedRegExBuilder;
import org.jooq.debug.console.remote.ClientDebugger;
/**
@ -115,6 +118,21 @@ public class Console extends JFrame {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
JMenuItem regExpEditorMenuItem = new JMenuItem("Reg. Exp. Editor");
regExpEditorMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JDialog dialog = new JDialog(Console.this, "Reg. Exp Editor");
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.add(new JSedRegExBuilder("/foo/bar/gi", "axFooax\nbxfoobx"), BorderLayout.CENTER);
dialog.add(contentPane, BorderLayout.CENTER);
dialog.setSize(600, 400);
dialog.setVisible(true);
dialog.setLocationRelativeTo(Console.this);
}
});
fileMenu.add(regExpEditorMenuItem);
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.setMnemonic('x');
exitMenuItem.addActionListener(new ActionListener() {
@ -153,15 +171,17 @@ public class Console extends JFrame {
final JDialog aboutDialog = new JDialog(Console.this, "About jOOQ Console", ModalityType.APPLICATION_MODAL);
aboutDialog.setResizable(false);
Container contentPane = aboutDialog.getContentPane();
JPanel centerPane = new JPanel(new GridBagLayout());
centerPane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
centerPane.add(new JLabel("jOOQ library: "), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
centerPane.add(new JLabel("Lukas Eder"), new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
centerPane.add(new JLabel("jOOQ Console: "), new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
centerPane.add(new JLabel("Christopher Deckers"), new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
centerPane.add(new JLabel("License: "), new GridBagConstraints(0, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
centerPane.add(new JLabel("Apache License, Version 2.0"), new GridBagConstraints(1, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
centerPane.add(new JLabel("Web site: "), new GridBagConstraints(0, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
JTabbedPane tabbedPane = new JTabbedPane();
JPanel aboutPane = new JPanel(new GridBagLayout());
aboutPane.setOpaque(false);
aboutPane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
aboutPane.add(new JLabel("jOOQ library: "), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
aboutPane.add(new JLabel("Lukas Eder"), new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
aboutPane.add(new JLabel("jOOQ Console: "), new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
aboutPane.add(new JLabel("Christopher Deckers"), new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
aboutPane.add(new JLabel("License: "), new GridBagConstraints(0, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
aboutPane.add(new JLabel("Apache License, Version 2.0"), new GridBagConstraints(1, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
aboutPane.add(new JLabel("Web site: "), new GridBagConstraints(0, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
JLabel siteLabel = new JLabel("http://www.jooq.org");
siteLabel.setForeground(Color.BLUE);
Map<TextAttribute, Object> attributeMap = new HashMap<TextAttribute, Object>();
@ -179,8 +199,30 @@ public class Console extends JFrame {
}
}
});
centerPane.add(siteLabel, new GridBagConstraints(1, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
contentPane.add(centerPane, BorderLayout.CENTER);
aboutPane.add(siteLabel, new GridBagConstraints(1, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 0, 0), 0, 0));
tabbedPane.addTab("About", aboutPane);
JPanel disclaimerPane = new JPanel(new BorderLayout());
disclaimerPane.setBorder(BorderFactory.createEmptyBorder(2, 5, 5, 5));
disclaimerPane.setOpaque(false);
JTextArea textArea = new JTextArea(
"This software is provided by the copyright holders and contributors \"as is\"" +
" and any express or implied warranties, including, but not limited to, the" +
" implied warranties of merchantability and fitness for a particular purpose" +
" are disclaimed. In no event shall the copyright owner or contributors be" +
" liable for any direct, indirect, incidental, special, exemplary, or" +
" consequential damages (including, but not limited to, procurement of" +
" substitute goods or services; loss of use, data, or profits; or business" +
" interruption) however caused and on any theory of liability, whether in" +
" contract, strict liability, or tort (including negligence or otherwise)" +
" arising in any way out of the use of this software, even if advised of the" +
" possibility of such damage."
);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
disclaimerPane.add(new JScrollPane(textArea));
tabbedPane.addTab("Disclaimer", disclaimerPane);
contentPane.add(tabbedPane, BorderLayout.CENTER);
JPanel southPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
@ -191,7 +233,7 @@ public class Console extends JFrame {
});
southPane.add(okButton);
contentPane.add(southPane, BorderLayout.SOUTH);
aboutDialog.pack();
aboutDialog.setSize(500, 400);
aboutDialog.setLocationRelativeTo(Console.this);
aboutDialog.setVisible(true);
}

View File

@ -86,6 +86,7 @@ import org.jooq.debug.console.misc.CheckBoxNode;
import org.jooq.debug.console.misc.CheckBoxNodeEditor;
import org.jooq.debug.console.misc.CheckBoxNodeRenderer;
import org.jooq.debug.console.misc.InvisibleSplitPane;
import org.jooq.debug.console.misc.TreeDataTip;
/**
* @author Christopher Deckers
@ -111,16 +112,18 @@ public class DebuggerPane extends JPanel {
setOpaque(false);
this.debugger = debugger;
JPanel westPane = new JPanel(new BorderLayout());
westPane.setBorder(BorderFactory.createTitledBorder("Breakpoints"));
westPane.setOpaque(false);
JPanel breakpointAddPane = new JPanel(new GridBagLayout());
breakpointAddPane.setOpaque(false);
breakpointAddPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
breakpointAddPane.add(new JLabel("Name "), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
final JTextField addBreakpointTextField = new JTextField(7);
breakpointAddPane.add(addBreakpointTextField, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
breakpointAddPane.add(addBreakpointTextField, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 0, 0), 0, 0));
final JButton addBreakpointButton = new JButton("Add");
addBreakpointButton.setOpaque(false);
addBreakpointButton.setEnabled(false);
breakpointAddPane.add(addBreakpointButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 0, 0), 0, 0));
breakpointAddPane.add(addBreakpointButton, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 0, 0), 0, 0));
addBreakpointTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
@ -205,6 +208,7 @@ public class DebuggerPane extends JPanel {
breakpointTree.setCellEditor(new CheckBoxNodeEditor(breakpointTree));
breakpointTree.setCellRenderer(new CheckBoxNodeRenderer(breakpointTree));
breakpointTree.setEditable(true);
TreeDataTip.activate(breakpointTree);
JScrollPane breakpointTreeScrollPane = new JScrollPane(breakpointTree);
breakpointTreeScrollPane.setPreferredSize(new Dimension(200, 200));
westPane.add(breakpointTreeScrollPane, BorderLayout.CENTER);
@ -509,9 +513,19 @@ public class DebuggerPane extends JPanel {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[0].getLastPathComponent();
if(node instanceof CheckBoxNode) {
Object o = node.getUserObject();
eastPane.add(new BreakpointEditor(this, (Breakpoint)o));
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(BorderFactory.createTitledBorder("Breakpoint configuration"));
contentPane.setOpaque(false);
BreakpointEditor c = new BreakpointEditor(this, (Breakpoint)o);
contentPane.add(c);
eastPane.add(contentPane);
} else if(node instanceof BreakpointHitNode) {
eastPane.add(new BreakpointHitEditor(debugger, this, (BreakpointHitNode)node));
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(BorderFactory.createTitledBorder("Breakpoint hit details"));
contentPane.setOpaque(false);
BreakpointHitEditor c = new BreakpointHitEditor(debugger, this, (BreakpointHitNode)node);
contentPane.add(c);
eastPane.add(contentPane);
}
}
eastPane.revalidate();

View File

@ -0,0 +1,206 @@
/**
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
* Christopher Deckers, chrriis@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.debug.console.misc;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseEvent;
import javax.swing.CellRendererPane;
import javax.swing.JComponent;
import javax.swing.JToolTip;
import javax.swing.JTree;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
public class TreeDataTip {
private TreeDataTip() {}
public static void activate(final JTree tree) {
MouseInputListener dataTipListener = new MouseInputAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
showTip(e.getPoint());
}
@Override
public void mouseMoved(MouseEvent e) {
showTip(e.getPoint());
}
@Override
public void mouseExited(MouseEvent e) {
hideTip();
}
@Override
public void mousePressed(MouseEvent e) {
hideTip();
}
private Popup popup;
private int currentRow = -1;
private void hideTip() {
if(popup != null) {
popup.hide();
popup = null;
}
}
private void showTip(Point mousePosition) {
int row = tree.getRowForLocation(mousePosition.x, mousePosition.y);
if(row != currentRow) {
hideTip();
currentRow = row;
if(row >= 0) {
TreePath treePath = tree.getPathForRow(row);
TreeCellRenderer renderer = tree.getCellRenderer();
boolean isSelected = false;//breakpointTree.isPathSelected(treePath);
boolean isExpanded = tree.isExpanded(treePath);
boolean hasFocus = false;//tree.hasFocus() && rowIndex == tree.getLeadSelectionRow();
Object item = treePath.getLastPathComponent();
boolean isLeaf = tree.getModel().isLeaf(item);
final JComponent rendererComponent = (JComponent)renderer.getTreeCellRendererComponent(tree, item, isSelected, isExpanded, isLeaf, row, hasFocus);
rendererComponent.setFont(tree.getFont());
Rectangle visRect = tree.getVisibleRect();
Rectangle cellBounds = tree.getPathBounds(treePath);
Rectangle visibleCellRectangle = cellBounds.intersection(visRect);
if (!visibleCellRectangle.contains(mousePosition)) {
return;
}
Dimension rendCompDim = rendererComponent.getMinimumSize();
Rectangle rendCompBounds = new Rectangle(cellBounds.getLocation(), rendCompDim);
visRect.x -= 1000;
visRect.width += 1000;
visRect.y -= 1000;
visRect.height += 2000;
// We do not care about vertical visibility.
rendCompBounds.height = 1;
if(cellBounds.contains(rendCompBounds) && visRect.contains(rendCompBounds)) {
return;
}
Dimension preferredSize = rendererComponent.getPreferredSize();
Point tipPosition = cellBounds.getLocation();
int width = Math.max(cellBounds.width, preferredSize.width);
int height = cellBounds.height;//Math.max(cellBounds.height, preferredSize.height); // We don't care about vertical visibility
Dimension tipDimension = new Dimension(width, height);
final Color backgroundColor = tree.getBackground();
class DataTipComponent extends JToolTip {
private CellRendererPane rendererPane = new CellRendererPane();
private boolean isHeavyWeight;
public DataTipComponent() {
add(rendererPane);
setFocusable(false);
setBorder(null);
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK);
}
@Override
public void updateUI() {
}
@Override
public boolean contains(int x, int y) {
return isHeavyWeight;
}
@Override
public void paintComponent(Graphics g) {
// Leave the component's opacity settings as is, just paint the background myself.
// This seems to be the only viable solution: DefaultTableCellRenderer overrides isOpaque() and returns
// true only if renderer color does not equal parent color. The problem is that rendererPane.paintComponent()
// re-parents the renderer.
g.setColor(backgroundColor);
int width = getWidth();
int height = getHeight();
g.fillRect(0, 0, width, height);
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
g.setClip(1, 1, width - 2, height - 2);
int row = currentRow;
TreePath treePath = tree.getPathForRow(row);
boolean isSelected = false;//breakpointTree.isPathSelected(treePath);
boolean isExpanded = tree.isExpanded(treePath);
boolean hasFocus = false;//tree.hasFocus() && rowIndex == tree.getLeadSelectionRow();
Object item = treePath.getLastPathComponent();
boolean isLeaf = tree.getModel().isLeaf(item);
TreeCellRenderer renderer = tree.getCellRenderer();
JComponent rendererComponent = (JComponent)renderer.getTreeCellRendererComponent(tree, item, isSelected, isExpanded, isLeaf, row, hasFocus);
rendererComponent.setFont(tree.getFont());
rendererPane.paintComponent(g, rendererComponent, this, 1, 1, width - 1, height - 1);
}
public void setHeavyWeight(boolean isHeavyWeight) {
this.isHeavyWeight = isHeavyWeight;
}
}
DataTipComponent dataTipComponent = new DataTipComponent();
Dimension tipDimensionClipped = new Dimension(tipDimension.width, tipDimension.height);
Window windowAncestor = SwingUtilities.getWindowAncestor(tree);
GraphicsConfiguration gc = windowAncestor.getGraphicsConfiguration();
Rectangle screenBounds = gc.getBounds();
// Chrriis: we add the border around, not in
Point tipScreenPosition = new Point(tipPosition.x, tipPosition.y);
SwingUtilities.convertPointToScreen(tipScreenPosition, tree);
Point tipPositionClipped = new Point();
tipPositionClipped.x = Math.max(tipScreenPosition.x - 1, screenBounds.x);
tipPositionClipped.y = Math.max(tipScreenPosition.y - 1, screenBounds.y);
// Chrriis: we add the border around, not in
tipDimensionClipped.width = Math.min(screenBounds.x + screenBounds.width - tipPositionClipped.x, tipDimensionClipped.width + 2);
tipDimensionClipped.height = Math.min(screenBounds.y + screenBounds.height - tipPositionClipped.y, tipDimensionClipped.height + 2);
SwingUtilities.convertPointFromScreen(tipPositionClipped, tree);
dataTipComponent.setPreferredSize(tipDimensionClipped);
SwingUtilities.convertPointToScreen(tipPosition, tree);
PopupFactory popupFactory = PopupFactory.getSharedInstance();
popup = popupFactory.getPopup(tree, dataTipComponent, tipPosition.x - 1, tipPosition.y - 1);
popup.show();
Window componentWindow = SwingUtilities.windowForComponent(tree);
Window tipWindow = SwingUtilities.windowForComponent(dataTipComponent);
boolean isHeavyWeight = tipWindow != null && tipWindow != componentWindow;
dataTipComponent.setHeavyWeight(isHeavyWeight);
}
}
}
};
tree.addMouseListener(dataTipListener);
tree.addMouseMotionListener(dataTipListener);
}
}

View File

@ -59,7 +59,21 @@ public class ClientStatementExecutionResultSetResult implements StatementExecuti
columnNames = rsResult.getColumnNames();
typeInfos = rsResult.getTypeInfos();
columnClasses = rsResult.getColumnClasses();
rowData = rsResult.getRowData();
Object[][] rowData_ = rsResult.getRowData();
rowData = new Object[rowData_.length][];
for(int i=0; i<rowData_.length; i++) {
Object[] columnData_ = rowData_[i];
Object[] columnData = new Object[columnData_.length];
for(int j=0; j<columnData_.length; j++) {
Object o = columnData_[j];
if(o != null && !(o instanceof Serializable)) {
// Best effort conversion because we are in remote mode...
o = String.valueOf(o);
}
columnData[j] = o;
}
rowData[i] = columnData;
}
rowCount = rsResult.getRowCount();
resultSetParsingDuration = rsResult.getResultSetParsingDuration();
retainParsedRSDataRowCountThreshold = rsResult.getRetainParsedRSDataRowCountThreshold();