/*
* Copyright (C) 2012 Timo Vesalainen
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.vesalainen.parsers.sql.dsql.ui.action;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.EnumSet;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.JTextPane;
import javax.swing.Timer;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.StyledEditorKit.ForegroundAction;
import static org.vesalainen.parser.ParserFeature.*;
import org.vesalainen.parser.util.Input;
import org.vesalainen.parser.util.InputReader;
import org.vesalainen.parser.util.OffsetLocatorException;
import org.vesalainen.parsers.sql.Engine;
import org.vesalainen.parsers.sql.ErrorReporter;
import org.vesalainen.parsers.sql.ErrorReporter.Level;
import org.vesalainen.parsers.sql.SQLLocator;
import org.vesalainen.parsers.sql.SelectStatement;
import org.vesalainen.parsers.sql.Statement;
import org.vesalainen.parsers.sql.dsql.ui.I18n;
import org.vesalainen.parsers.sql.dsql.ui.WorkBench;
/**
* @author Timo Vesalainen
*/
public class DSqlParseAction extends AbstractAction implements DocumentListener, SQLLocator, ErrorReporter, UndoableEditListener
{
public static final String PropertyName = "statement";
private final Timer timer;
private WorkBench workBench;
private UndoableEditListener listener;
private boolean off;
private JTextPane sqlPane;
private final ForegroundAction blackAction;
private final ForegroundAction redAction;
private final ForegroundAction blueAction;
private final ForegroundAction grayAction;
private final ForegroundAction orangeAction;
private Level errorLevel;
private InputReader reader;
private boolean readonly;
public DSqlParseAction(WorkBench workBench, UndoableEditListener listener, boolean readonly)
{
super(null);
this.workBench = workBench;
this.listener = listener;
this.readonly = readonly;
timer = new Timer(500, this);
timer.stop();
timer.setRepeats(false);
timer.setActionCommand("TimerAction");
blackAction = new StyledEditorKit.ForegroundAction("Black", Color.BLACK);
redAction = new StyledEditorKit.ForegroundAction("Red", Color.red);
blueAction = new StyledEditorKit.ForegroundAction("Blue", Color.BLUE);
grayAction = new StyledEditorKit.ForegroundAction("Green", Color.LIGHT_GRAY);
orangeAction = new StyledEditorKit.ForegroundAction("Orange", Color.ORANGE);
}
@Override
public void actionPerformed(ActionEvent e)
{
if (timer.getActionCommand().equals(e.getActionCommand()))
{
firePropertyChange(PropertyName, null, null);
sqlPane = workBench.getActiveTextPane();
sqlPane.setToolTipText("");
color(blackAction, 0, sqlPane.getDocument().getLength());
String sql = sqlPane.getText();
if (!sql.isEmpty())
{
if (reader == null)
{
reader = Input.getInstance(sql, EnumSet.of(UseOffsetLocatorException));
}
else
{
reader.reuse(sql);
}
try
{
errorLevel = ErrorReporter.Level.Ok;
Engine engine = workBench.getEngine();
engine.check(reader, this);
Statement statement = engine.prepare(sql);
if (readonly)
{
if (!(statement.isSelectStatement()))
{
JOptionPane.showMessageDialog(workBench.getFrame(), I18n.get("IN READONLY MODE"), I18n.get("REFUSED"), JOptionPane.ERROR_MESSAGE);
return;
}
}
statement.check(engine, this);
if (errorLevel != Level.Fatal)
{
firePropertyChange(PropertyName, null, statement);
}
}
catch (OffsetLocatorException ex)
{
sqlPane.setToolTipText(ex.getLocalizedMessage());
color(redAction, ex.getStart(), ex.getEnd());
}
}
}
}
private void color(Action action, int start, int end)
{
try
{
setOff();
int save = sqlPane.getCaretPosition();
sqlPane.setCaretPosition(start);
sqlPane.moveCaretPosition(end);
action.actionPerformed(null);
sqlPane.setCaretPosition(save);
setOn();
}
catch (IllegalArgumentException ex)
{
ex.printStackTrace();
}
}
@Override
public void locate(int start, int end, SQLLocator.Type type)
{
switch (type)
{
case COMMENT:
color(grayAction, start, end);
break;
case RESERVED_WORD:
color(blueAction, start, end);
break;
default:
assert false;
}
}
@Override
public void report(String message, ErrorReporter.Level level, String source, int start, int end)
{
switch (level)
{
case Fatal:
color(redAction, start, end);
break;
case Hint:
color(orangeAction, start, end);
break;
default:
assert false;
}
sqlPane.setToolTipText(message);
if (level.ordinal() > errorLevel.ordinal())
{
errorLevel = level;
}
}
@Override
public void replace(String newText, int start, int end)
{
setOff();
int save = sqlPane.getCaretPosition();
sqlPane.setCaretPosition(start);
sqlPane.moveCaretPosition(end);
sqlPane.replaceSelection(newText);
sqlPane.setCaretPosition(save);
setOn();
}
@Override
public void insertUpdate(DocumentEvent e)
{
timer.restart();
}
@Override
public void removeUpdate(DocumentEvent e)
{
timer.restart();
}
@Override
public void changedUpdate(DocumentEvent e)
{
if (!off)
{
timer.restart();
}
}
public void setOn()
{
this.off = false;
}
public void setOff()
{
this.off = true;
}
@Override
public void undoableEditHappened(UndoableEditEvent e)
{
if (!off)
{
listener.undoableEditHappened(e);
}
}
}