/* * 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; import org.vesalainen.parsers.sql.dsql.ui.action.InsertPropertiesHandler; import org.vesalainen.parsers.sql.dsql.ui.action.GenerateSelectHandler; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.Text; import org.vesalainen.parsers.sql.dsql.ui.action.MetadataTreeAction; import org.vesalainen.parsers.sql.dsql.ui.action.RedoAction; import org.vesalainen.parsers.sql.dsql.ui.action.UndoAction; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextPane; import javax.swing.KeyStroke; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import javax.swing.undo.UndoManager; import org.vesalainen.parsers.sql.dsql.DSQLEngine; import org.vesalainen.parsers.sql.dsql.ui.action.AboutAction; import org.vesalainen.parsers.sql.dsql.ui.action.DSqlParseAction; import org.vesalainen.parsers.sql.dsql.ui.action.ExecuteAction; import org.vesalainen.parsers.sql.dsql.ui.action.ExportCSVAction; import org.vesalainen.parsers.sql.dsql.ui.action.FetchResultHandler; import org.vesalainen.parsers.sql.dsql.ui.action.OpenSQLFileAction; import org.vesalainen.parsers.sql.dsql.ui.action.PersistenceHandler; import org.vesalainen.parsers.sql.dsql.ui.action.PrintAction; import org.vesalainen.parsers.sql.dsql.ui.action.DSQLHelpAction; import org.vesalainen.parsers.sql.dsql.ui.action.SaveSQLFileAction; import org.vesalainen.parsers.sql.dsql.ui.action.SelectForUpdateAction; import org.vesalainen.parsers.sql.dsql.ui.action.ViewAction; import org.vesalainen.parsers.sql.dsql.ui.plugin.MailPlugin; /** * @author Timo Vesalainen */ public class WorkBench extends WindowAdapter implements VetoableChangeListener { static final String TITLE = I18n.get("DATASTORE QUERY VERSION"); static final String SqlProperty = WorkBench.class.getName()+".sql"; final static Cursor busyCursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); final static Cursor defaultCursor = Cursor.getDefaultCursor(); public static final List<Image> icons = new ArrayList<>(); static { icons.add(new ImageIcon(WorkBench.class.getResource("images/dsql16.png")).getImage()); icons.add(new ImageIcon(WorkBench.class.getResource("images/dsql32.png")).getImage()); icons.add(new ImageIcon(WorkBench.class.getResource("images/dsql48.png")).getImage()); icons.add(new ImageIcon(WorkBench.class.getResource("images/dsql64.png")).getImage()); } private DSQLEngine engine; private JFrame frame; private JMenuBar menuBar; private final JScrollPane upperPane; private final JScrollPane resultPane; private final JSplitPane splitPane; final JTextPane sqlPane; private JButton executeButton; private JButton selectAndUpdateButton; final String storedStatementsKind; private JButton commitButton; private JButton rollbackButton; private JButton deleteRowButton; private DSqlParseAction parseAction; private JPanel buttonPanel; private JMenu sourceMenu; private JMenu actionMenu; private FetchResultHandler fetchResultHandler; private ExecuteAction executeAction; private PersistenceHandler persistenceHandler; private JButton printButton; private JMenu helpMenu; private String title; private ExportCSVAction exportCSVAction; private boolean embed; private boolean readonly; private String savedSql; private JButton viewButton; public WorkBench(Properties properties) throws IOException, InterruptedException { this(properties, false, false); } public WorkBench(Properties properties, boolean embed, boolean readonly) throws IOException, InterruptedException { this.storedStatementsKind = properties.getProperty("stored-statements-kind", "DSQLStatements"); this.embed = embed; this.readonly = readonly; engine = DSQLEngine.getProxyInstance( properties.getProperty(CredentialsDialog.REMOTESERVER), properties.getProperty(CredentialsDialog.REMOTENAMESPACE), properties.getProperty(CredentialsDialog.REMOTEUSER) ); title = TITLE+" - "+properties.getProperty(CredentialsDialog.REMOTENAMESPACE)+"."+properties.getProperty(CredentialsDialog.REMOTESERVER); frame = new JFrame(title); frame.addWindowListener(this); if (!embed) { Toolkit.getDefaultToolkit().getSystemEventQueue().push(new ExceptionHandler()); } frame.setIconImages(icons); sqlPane = new JTextPane(); sqlPane.getDocument().putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n"); sqlPane.setPreferredSize(new Dimension(700, 200)); Map<Object,Action> actions = new HashMap<>(); for (Action action : sqlPane.getActions()) { actions.put(action.getValue(Action.NAME), action); } Document document = sqlPane.getDocument(); UndoManager undoManager = new UndoManager(); parseAction = new DSqlParseAction(this, undoManager, readonly); document.addDocumentListener(parseAction); document.addUndoableEditListener(parseAction); menuBar = new JMenuBar(); frame.setJMenuBar(menuBar); JMenu fileMenu = new JMenu(I18n.get("FILE")); menuBar.add(fileMenu); persistenceHandler = new PersistenceHandler(this, storedStatementsKind); OpenSQLFileAction openFileStatementAction = new OpenSQLFileAction(this, persistenceHandler); fileMenu.add(openFileStatementAction); SaveSQLFileAction saveSQLFileAction = new SaveSQLFileAction(this); fileMenu.add(saveSQLFileAction); persistenceHandler.addVetoableChangeListener(saveSQLFileAction); fileMenu.addSeparator(); persistenceHandler.addVetoableChangeListener(this); for (Action action : persistenceHandler.getActions()) { fileMenu.add(action); } fileMenu.addSeparator(); JMenu editMenu = new JMenu(I18n.get("EDIT")); menuBar.add(editMenu); editMenu.add(new UndoAction(I18n.get("UNDO"), undoManager)); editMenu.add(new RedoAction(I18n.get("REDO"), undoManager)); JMenuItem menuItem = new JMenuItem(new DefaultEditorKit.CutAction()); menuItem.setText(I18n.get("CUT")); menuItem.setMnemonic(KeyEvent.VK_T); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK)); editMenu.add(menuItem); menuItem = new JMenuItem(new DefaultEditorKit.CopyAction()); menuItem.setText(I18n.get("COPY")); menuItem.setMnemonic(KeyEvent.VK_C); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK)); menuItem.addActionListener(new TransferActionListener()); editMenu.add(menuItem); menuItem = new JMenuItem(new DefaultEditorKit.PasteAction()); menuItem.setText(I18n.get("PASTE")); menuItem.setMnemonic(KeyEvent.VK_P); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK)); editMenu.add(menuItem); upperPane = new JScrollPane(sqlPane); sourceMenu = new JMenu(I18n.get("SOURCE")); menuBar.add(sourceMenu); InsertPropertiesHandler insertPropertiesHandler = new InsertPropertiesHandler(sqlPane); MetadataTreeAction insertPropertiesAction = new MetadataTreeAction( this, I18n.get("INSERT PROPERTIES"), I18n.get("INSERT PROPERTIES AT THE CURSOR POSITION"), engine.getStatistics(), insertPropertiesHandler ); sourceMenu.add(insertPropertiesAction).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, InputEvent.ALT_DOWN_MASK)); GenerateSelectHandler generateSelectHandler = new GenerateSelectHandler(sqlPane); MetadataTreeAction generateSelectAction = new MetadataTreeAction( this, I18n.get("GENERATE SELECT"), I18n.get("GENERATE A SELECT STATEMENT"), engine.getStatistics(), generateSelectHandler ); sourceMenu.add(generateSelectAction).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, InputEvent.ALT_DOWN_MASK)); resultPane = new JScrollPane(); splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, upperPane, resultPane); splitPane.setDividerLocation(0.5); JPanel contentPane = new JPanel(new BorderLayout()); contentPane.add(splitPane, BorderLayout.CENTER); buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout()); contentPane.add(buttonPanel, BorderLayout.SOUTH); actionMenu = new JMenu(I18n.get("ACTIONS")); menuBar.add(actionMenu); executeAction = new ExecuteAction(frame); parseAction.addPropertyChangeListener(executeAction); executeButton = new JButton(executeAction); buttonPanel.add(executeButton); actionMenu.add(executeButton.getAction()); persistenceHandler.setExecuteAction(executeAction); SelectForUpdateAction selectForUpdateAction = new SelectForUpdateAction(frame); parseAction.addPropertyChangeListener(selectForUpdateAction); if (!readonly) { selectAndUpdateButton = new JButton(selectForUpdateAction); buttonPanel.add(selectAndUpdateButton); actionMenu.add(selectAndUpdateButton.getAction()); } fetchResultHandler = new FetchResultHandler(frame, resultPane); executeAction.addPropertyChangeListener(fetchResultHandler); selectForUpdateAction.addPropertyChangeListener(fetchResultHandler); deleteRowButton = new JButton(fetchResultHandler.getDeleteRowAction()); buttonPanel.add(deleteRowButton); actionMenu.add(deleteRowButton.getAction()); commitButton = new JButton(fetchResultHandler.getCommitAction()); buttonPanel.add(commitButton); actionMenu.add(commitButton.getAction()); rollbackButton = new JButton(fetchResultHandler.getRollbackAction()); buttonPanel.add(rollbackButton); actionMenu.add(rollbackButton.getAction()); PrintAction printAction = new PrintAction(frame); fetchResultHandler.addPropertyChangeListener(printAction); executeAction.addPropertyChangeListener(printAction); persistenceHandler.addVetoableChangeListener(printAction); printButton = new JButton(printAction); buttonPanel.add(printButton); persistenceHandler.addAutoAction(printAction); if (embed) { ViewAction viewAction = new ViewAction(printAction); fetchResultHandler.addPropertyChangeListener(viewAction); viewButton = new JButton(viewAction); buttonPanel.add(viewButton); persistenceHandler.addAutoAction(viewAction); } frame.setContentPane(contentPane); helpMenu = new JMenu(I18n.get("HELP")); menuBar.add(helpMenu); helpMenu.add(new DSQLHelpAction()); helpMenu.add(new AboutAction()); exportCSVAction = new ExportCSVAction(); fetchResultHandler.addPropertyChangeListener(exportCSVAction); persistenceHandler.addVetoableChangeListener(exportCSVAction); fileMenu.add(exportCSVAction); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(!embed); frame.setSize(800, 580); addFetchResultPlugin(new MailPlugin(engine)); } public void setVisible(boolean visible) { frame.setVisible(visible); } public void open() { persistenceHandler.open(true); } public void close() { engine.exit(); } /** * Adds a FetchResultHandler. * @param plugin */ public void addFetchResultPlugin(FetchResultPlugin plugin) { Action action = (Action) plugin; JButton button = new JButton(action); buttonPanel.add(button); actionMenu.add(action); plugin.setFrame(frame); fetchResultHandler.addPropertyChangeListener(plugin); persistenceHandler.addVetoableChangeListener(plugin); persistenceHandler.addAutoAction(plugin); } @Override public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { Entity entity = (Entity) evt.getNewValue(); String name = ""; String sql = null; switch (evt.getPropertyName()) { case PersistenceHandler.OPEN: if (entity != null) { // Open Text text = (Text) entity.getProperty(SqlProperty); if (text != null) { sql = text.getValue(); } name = entity.getKey().getName(); } break; case PersistenceHandler.SAVE: if (entity != null) { // Save Text text = new Text(sqlPane.getText()); entity.setUnindexedProperty(SqlProperty, text); if (text != null) { sql = text.getValue(); } name = entity.getKey().getName(); } else { // Remove } break; } setSql(sql, evt); frame.setTitle(name+" - "+title); } private void setSql(String sql, PropertyChangeEvent evt) throws PropertyVetoException { if (savedSql != null && !savedSql.equals(sqlPane.getText())) { int confirm = JOptionPane.showConfirmDialog(frame, I18n.get("CONFIRMSQLOVERWRITE") ); if (confirm != JOptionPane.YES_OPTION) { throw new PropertyVetoException(I18n.get("REFUSED"), evt); } } sqlPane.setText(sql); savedSql = sql; } public JTextPane getActiveTextPane() { return sqlPane; } public ActionListener createActionListener(final Component component, final ActionListener actionListener) { ActionListener al = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { component.setCursor(busyCursor); component.repaint(); actionListener.actionPerformed(e); } finally { component.setCursor(defaultCursor); } } }; return al; } @Override public void windowClosing(WindowEvent e) { if (!embed) { engine.exit(); System.exit(0); } } public DSQLEngine getEngine() { return engine; } public JFrame getFrame() { return frame; } /** * @param args the command line arguments */ public static void main(String[] args) { try { if (args.length != 1) { System.err.println("usage: java ... <properties file>"); System.exit(-1); } File file = new File(args[0]); CredentialsDialog dia = new CredentialsDialog(file); if (dia.input()) { WorkBench workBench = new WorkBench(dia.getProperties()); } else { System.exit(-1); } } catch (Throwable ex) { ex = ex.getCause() == null ? ex : ex.getCause(); JOptionPane.showMessageDialog(null, ex.getLocalizedMessage(), ex.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); System.exit(-1); } } }