blob: e0213ef8f3c3a3eefcc529c5821d58d29ad7a36c [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 com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import org.apache.cayenne.configuration.event.QueryEvent;
import org.apache.cayenne.map.QueryDescriptor;
import org.apache.cayenne.map.SQLTemplateDescriptor;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.util.DbAdapterInfo;
import org.apache.cayenne.modeler.util.JUndoableCayenneTextPane;
import org.apache.cayenne.swing.components.textpane.JCayenneTextPane;
import org.apache.cayenne.swing.components.textpane.syntax.SQLSyntaxConstants;
import org.apache.cayenne.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A panel for configuring SQL scripts of a SQL template.
*
*/
public class SQLTemplateScriptsTab extends JPanel {
private static final String DEFAULT_LABEL = "Default";
private static final Logger logger = LoggerFactory.getLogger(SQLTemplateScriptsTab.class);
protected ProjectController mediator;
protected JList<String> scripts;
protected List<String> keys;
protected PanelBuilder builder;
protected CellConstraints cc;
protected JCayenneTextPane textPane;
protected List<JCayenneTextPane> panes;
protected ListSelectionListener scriptRefreshHandler;
public SQLTemplateScriptsTab(ProjectController mediator) {
this.mediator = mediator;
initView();
}
private void prepareScriptAreas() {
for(String key : DbAdapterInfo.getStandardAdapters()) {
JCayenneTextPane currPane = new JUndoableCayenneTextPane(new SQLSyntaxConstants());
currPane.setName(key);
currPane.getDocument().addDocumentListener(new CustomListener(currPane.getName()));
builder.add(currPane.getScrollPane(), cc.xy(3, 2));
panes.add(currPane);
}
}
protected void initView() {
// create widgets, etc.
scriptRefreshHandler = new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
displayScript();
}
}
};
scripts = new JList<>();
scripts.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
scripts.setCellRenderer(new DbAdapterListRenderer(DbAdapterInfo.getStandardAdapterLabels()));
keys = new ArrayList<>(DbAdapterInfo.getStandardAdapters().length + 1);
keys.addAll(Arrays.asList(DbAdapterInfo.getStandardAdapters()));
Collections.sort(keys);
keys.add(0, DEFAULT_LABEL);
scripts.setModel(new DefaultComboBoxModel<>(keys.toArray(new String[0])));
// assemble
cc = new CellConstraints();
textPane = new JUndoableCayenneTextPane(new SQLSyntaxConstants());
textPane.setName(DEFAULT_LABEL);
textPane.getDocument().addDocumentListener(new CustomListener(textPane.getName()));
panes = new ArrayList<>();
panes.add(textPane);
builder = new PanelBuilder(new FormLayout(
"fill:100dlu, 3dlu, fill:100dlu:grow",
"3dlu, fill:100dlu:grow"));
// orderings table must grow as the panel is resized
builder.add(new JScrollPane(
scripts,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), cc.xy(1, 2));
builder.add(textPane.getScrollPane(), cc.xy(3, 2));
setLayout(new BorderLayout());
add(builder.getPanel(), BorderLayout.CENTER);
prepareScriptAreas();
}
void initFromModel() {
QueryDescriptor query = mediator.getCurrentQuery();
if (query == null || !QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) {
setVisible(false);
return;
}
// select default script.. display it bypassing the listener...
scripts.removeListSelectionListener(scriptRefreshHandler);
scripts.setSelectedIndex(0);
displayScript();
scripts.addListSelectionListener(scriptRefreshHandler);
setVisible(true);
}
/**
* Returns SQLTemplate text for current selection.
*/
String getSQLTemplate(String key) {
if (key == null) {
return null;
}
SQLTemplateDescriptor query = getQuery();
if (query == null) {
return null;
}
return (key.equals(DEFAULT_LABEL)) ? query.getSql() : query
.getAdapterSql().get(key);
}
SQLTemplateDescriptor getQuery() {
QueryDescriptor query = mediator.getCurrentQuery();
return (query != null && QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) ?
(SQLTemplateDescriptor) query : null;
}
/**
* Shows selected script in the editor.
*/
void displayScript() {
SQLTemplateDescriptor query = getQuery();
if (query == null) {
return;
}
String key = scripts.getSelectedValue();
if (key == null) {
return;
}
final String text = (key.equals(DEFAULT_LABEL)) ? query.getSql() : query
.getAdapterSql().get(key);
for (final JCayenneTextPane textPane : panes) {
if (key.equals(textPane.getName())) {
textPane.setDocumentTextDirect(text);
textPane.getScrollPane().setVisible(true);
textPane.getPane().requestFocusInWindow();
} else {
textPane.getScrollPane().setVisible(false);
}
}
}
void setSQL(DocumentEvent e, String key) {
if (key == null) {
return;
}
SQLTemplateDescriptor query = getQuery();
if (query == null) {
return;
}
Document doc = e.getDocument();
String text = null;
try {
text = doc.getText(0, doc.getLength());
} catch (BadLocationException ex) {
logger.warn("Error reading document", ex);
}
if (text != null) {
text = text.trim();
if (text.length() == 0) {
text = null;
}
}
// Compare the value before modifying the query - text pane
// will call "verify" even if no changes have occured....
if (key.equals(DEFAULT_LABEL)) {
if (!Util.nullSafeEquals(text, query.getSql())) {
query.setSql(text);
mediator.fireQueryEvent(new QueryEvent(this, query));
}
} else {
if (!Util.nullSafeEquals(text, query.getAdapterSql().get(key))) {
query.getAdapterSql().put(key, text);
mediator.fireQueryEvent(new QueryEvent(this, query));
}
}
}
final class CustomListener implements DocumentListener{
private String key;
public CustomListener(String key) {
this.key = key;
}
@Override
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void changedUpdate(DocumentEvent e) {
setSQL(e, key);
}
}
final class DbAdapterListRenderer extends DefaultListCellRenderer {
Map adapterLabels;
DbAdapterListRenderer(Map adapterLabels) {
this.adapterLabels = (adapterLabels != null)
? adapterLabels
: Collections.EMPTY_MAP;
}
public Component getListCellRendererComponent(
JList list,
Object object,
int index,
boolean selected,
boolean hasFocus) {
if (object instanceof Class) {
object = ((Class) object).getName();
}
Object label = adapterLabels.get(object);
if (label == null) {
label = object;
}
Component c = super.getListCellRendererComponent(
list,
label,
index,
selected,
hasFocus);
// grey out keys that have no SQL
setForeground(selected || getSQLTemplate(object.toString()) != null
? Color.BLACK
: Color.LIGHT_GRAY);
return c;
}
}
public int getSelectedIndex() {
return scripts.getSelectedIndex();
}
public void setSelectedIndex(int index) {
scripts.setSelectedIndex(index);
}
}