blob: 3520e95f5ebb991930d5132211f1ceb9561fd49f [file] [log] [blame]
/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
****************************************************************/
package org.apache.cayenne.modeler.editor;
import java.awt.BorderLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.apache.cayenne.configuration.event.QueryEvent;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.util.JUndoableCayenneTextPane;
import org.apache.cayenne.project.validation.EJBQLStatementValidator;
import org.apache.cayenne.project.validation.EJBQLStatementValidator.PositionException;
import org.apache.cayenne.map.EJBQLQueryDescriptor;
import org.apache.cayenne.map.QueryDescriptor;
import org.apache.cayenne.swing.components.textpane.JCayenneTextPane;
import org.apache.cayenne.swing.components.textpane.syntax.EJBQLSyntaxConstant;
import org.apache.cayenne.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EjbqlQueryScriptsTab extends JPanel implements DocumentListener {
private static final Logger logger = LoggerFactory.getLogger(EjbqlQueryScriptsTab.class);
protected ProjectController mediator;
protected JCayenneTextPane scriptArea;
private boolean updateDisabled;
protected EJBQLStatementValidator ejbqlQueryValidator = new EJBQLStatementValidator();
public EjbqlQueryScriptsTab(ProjectController mediator) {
this.mediator = mediator;
initView();
}
void displayScript() {
scriptArea.setDocumentTextDirect(getQuery().getEjbql());
updateDisabled = false;
}
private void initView() {
scriptArea = new JUndoableCayenneTextPane(new EJBQLSyntaxConstant());
scriptArea.getDocument().addDocumentListener(this);
scriptArea.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
}
public void insertUpdate(DocumentEvent e) {
try {
String text = scriptArea.getDocument().getText(e.getOffset(), 1);
if (text.equals(" ") || text.equals("\n") || text.equals("\t")) {
getQuery().setEjbql(scriptArea.getDocumentTextDirect());
validateEJBQL();
}
} catch (BadLocationException ex) {
logger.warn("Error reading document", ex);
}
}
public void removeUpdate(DocumentEvent e) {
getQuery().setEjbql(scriptArea.getDocumentTextDirect());
validateEJBQL();
}
});
scriptArea.getPane().addFocusListener(new FocusListener() {
EJBQLValidationThread thread;
public void focusGained(FocusEvent e) {
thread = new EJBQLValidationThread();
thread.start();
}
public void focusLost(FocusEvent e) {
thread.terminate();
}
});
scriptArea.getPane().addKeyListener(new KeyListener() {
boolean pasteOrCut;
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_END || e.getKeyCode() == KeyEvent.VK_HOME
|| e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_RIGHT
|| e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_UNDO) {
getQuery().setEjbql(scriptArea.getText());
validateEJBQL();
}
if ((e.getKeyCode() == KeyEvent.VK_V || e.getKeyCode() == KeyEvent.VK_X) && e.isControlDown()) {
pasteOrCut = true;
}
}
public void keyReleased(KeyEvent e) {
if ((pasteOrCut && e.getKeyCode() == KeyEvent.VK_CONTROL) || e.getKeyCode() == KeyEvent.VK_DELETE) {
scriptArea.removeHighlightText();
getQuery().setEjbql(scriptArea.getText());
validateEJBQL();
pasteOrCut = false;
}
}
public void keyTyped(KeyEvent e) {
}
});
setLayout(new BorderLayout());
add(scriptArea, BorderLayout.WEST);
add(scriptArea.getScrollPane(), BorderLayout.CENTER);
setVisible(true);
}
public void initFromModel() {
QueryDescriptor query = mediator.getCurrentQuery();
if (query == null || !QueryDescriptor.EJBQL_QUERY.equals(query.getType())) {
setVisible(false);
return;
}
scriptArea.setEnabled(true);
displayScript();
validateEJBQL();
setVisible(true);
}
EJBQLQueryDescriptor getQuery() {
QueryDescriptor query = mediator.getCurrentQuery();
return (query != null && QueryDescriptor.EJBQL_QUERY.equals(query.getType())) ?
(EJBQLQueryDescriptor) query : null;
}
void setEJBQL(DocumentEvent e) {
Document doc = e.getDocument();
try {
setEJBQL(doc.getText(0, doc.getLength()));
} catch (BadLocationException ex) {
logger.warn("Error reading document", ex);
}
}
void setEJBQL(String text) {
EJBQLQueryDescriptor query = getQuery();
if (query == null) {
return;
}
if (text != null && text.trim().isEmpty()) {
text = null;
}
// Compare the value before modifying the query - text area
// will call "verify" even if no changes have occured....
if (!Util.nullSafeEquals(text, query.getEjbql())) {
query.setEjbql(text);
mediator.fireQueryEvent(new QueryEvent(this, query));
}
}
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void changedUpdate(DocumentEvent e) {
if (!updateDisabled) {
setEJBQL(e);
}
}
void validateEJBQL() {
final PositionException positionException = ejbqlQueryValidator.validateEJBQL(getQuery());
if (positionException != null) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (positionException.getBeginLine() != null || positionException.getBeginColumn() != null
|| positionException.getLength() != null) {
scriptArea.setHighlightText(positionException.getBeginLine(),
positionException.getBeginColumn(), positionException.getLength(),
positionException.getMessage());
} else {
scriptArea.removeHighlightText();
}
}
});
}
}
}
class EJBQLValidationThread extends Thread {
volatile boolean running;
final Object timer = new Object();
int previousCaretPosition;
int validateCaretPosition;
static final int DELAY = 500;
EJBQLValidationThread() {
super("ejbql-validation-thread");
setDaemon(true);
}
public void run() {
running = true;
while (running) {
int caretPosition = scriptArea.getCaretPosition();
if (previousCaretPosition != 0 && previousCaretPosition == caretPosition
&& validateCaretPosition != previousCaretPosition) {
validateEJBQL();
validateCaretPosition = caretPosition;
}
previousCaretPosition = caretPosition;
synchronized (timer) {
try {
timer.wait(DELAY);
} catch (InterruptedException ignored) {
}
}
}
}
void terminate() {
synchronized (timer) {
running = false;
timer.notify();
}
}
}
}