org.jgrasstools.spatialite.SpatialiteController Maven / Gradle / Ivy
/*
* This file is part of JGrasstools (http://www.jgrasstools.org)
* (C) HydroloGIS - www.hydrologis.com
*
* JGrasstools 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 .
*/
package org.jgrasstools.spatialite;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextPane;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.EventListenerList;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import org.geotools.feature.DefaultFeatureCollection;
import org.jgrasstools.dbs.spatialite.ForeignKey;
import org.jgrasstools.dbs.spatialite.QueryResult;
import org.jgrasstools.dbs.spatialite.SpatialiteGeometryColumns;
import org.jgrasstools.dbs.spatialite.SpatialiteGeometryType;
import org.jgrasstools.dbs.spatialite.SpatialiteTableNames;
import org.jgrasstools.dbs.spatialite.jgt.SpatialiteDb;
import org.jgrasstools.dbs.spatialite.objects.ColumnLevel;
import org.jgrasstools.dbs.spatialite.objects.DbLevel;
import org.jgrasstools.dbs.spatialite.objects.TableLevel;
import org.jgrasstools.dbs.spatialite.objects.TypeLevel;
import org.jgrasstools.gears.io.vectorwriter.OmsVectorWriter;
import org.jgrasstools.gears.libs.logging.JGTLogger;
import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor;
import org.jgrasstools.gears.libs.monitor.LogProgressMonitor;
import org.jgrasstools.gears.spatialite.GTSpatialiteThreadsafeDb;
import org.jgrasstools.gui.console.LogConsoleController;
import org.jgrasstools.gui.utils.GuiBridgeHandler;
import org.jgrasstools.gui.utils.GuiUtilities;
import org.jgrasstools.gui.utils.GuiUtilities.IOnCloseListener;
import org.jgrasstools.gui.utils.ImageCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The spatialtoolbox view controller.
*
* @author Andrea Antonello (www.hydrologis.com)
*
*/
public abstract class SpatialiteController extends SpatialiteView implements IOnCloseListener {
private static final Logger logger = LoggerFactory.getLogger(SpatialiteView.class);
private static final long serialVersionUID = 1L;
private static final String SHAPEFILE_IMPORT = "import shapefile in selected table";
private static final String SHAPEFILE_CCREATE_FROM_SCHEMA = "create table from shapefile schema";
private static final String SHAPEFILE_TOOLTIP = "tools to deal with shapefiles";
private static final String SHAPEFILE = "shapefile";
private static final String SQL_TEMPLATES_TOOLTIP = "create a query based on a template";
private static final String SQL_TEMPLATES = "sql templates";
private static final String SQL_HISTORY_TOOLTIP = "select queries from the history";
private static final String SQL_HISTORY = "sql history";
private static final String DISCONNECT_TOOLTIP = "disconnect from current database";
private static final String DISCONNECT = "disconnect";
private static final String RUN_QUERY = "run query";
private static final String RUN_QUERY_TOOLTIP = "run the query in the SQL Editor";
private static final String RUN_QUERY_TO_FILE_TOOLTIP = "run the query in the SQL Editor and store result in file";
private static final String RUN_QUERY_TO_SHAPEFILE_TOOLTIP = "run the query in the SQL Editor and store result in a shapefile";
protected static final String VIEW_QUERY_TOOLTIP = "run spatial query and view the result in the 3D viewer";
private static final String SQL_EDITOR = "SQL Editor";
private static final String CLEAR_SQL_EDITOR = "clear SQL editor";
private static final String DATA_VIEWER = "Data viewer";
private static final String DATABASE_CONNECTIONS = "Database connection";
private static final String NEW = "new";
private static final String NEW_TOOLTIP = "create a new spatialite database";
private static final String CONNECT = "connect";
private static final String CONNECT_TOOLTIP = "connect to an existing spatialite database";
protected GuiBridgeHandler guiBridge;
protected IJGTProgressMonitor pm = new LogProgressMonitor();
protected GTSpatialiteThreadsafeDb currentConnectedDatabase;
private DbLevel currentDbLevel;
protected DbLevel currentSelectedDb;
protected TableLevel currentSelectedTable;
protected ColumnLevel currentSelectedColumn;
private Dimension preferredToolbarButtonSize = new Dimension(80, 50);
private Dimension preferredSqleditorButtonSize = new Dimension(30, 30);
private List oldSqlCommands = new ArrayList();
public SpatialiteController( GuiBridgeHandler guiBridge ) {
this.guiBridge = guiBridge;
setPreferredSize(new Dimension(900, 600));
init();
}
@SuppressWarnings({"serial"})
private void init() {
String[] oldSqlCommandsArray = GuiUtilities.getPreference("JGT_OLD_SQL_COMMANDS", new String[0]);
for( String oldSql : oldSqlCommandsArray ) {
oldSqlCommands.add(oldSql);
}
_limitCountTextfield.setText("1000");
_limitCountTextfield.setToolTipText("1000 is default and used when no valid number is supplied. -1 means no limit.");
_dataViewerTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
addDataTableContextMenu();
// WrapEditorKit kit = new WrapEditorKit();
// _sqlEditorArea.setEditorKit(kit);
SqlDocument doc = new SqlDocument();
_sqlEditorArea.setDocument(doc);
_newDbButton.setVerticalTextPosition(SwingConstants.BOTTOM);
_newDbButton.setHorizontalTextPosition(SwingConstants.CENTER);
_newDbButton.setText(NEW);
_newDbButton.setToolTipText(NEW_TOOLTIP);
_newDbButton.setPreferredSize(preferredToolbarButtonSize);
_newDbButton.setIcon(ImageCache.getInstance().getImage(ImageCache.NEW_DATABASE));
_newDbButton.addActionListener(e -> {
createNewDatabase();
});
_connectDbButton.setVerticalTextPosition(SwingConstants.BOTTOM);
_connectDbButton.setHorizontalTextPosition(SwingConstants.CENTER);
_connectDbButton.setText(CONNECT);
_connectDbButton.setToolTipText(CONNECT_TOOLTIP);
_connectDbButton.setPreferredSize(preferredToolbarButtonSize);
_connectDbButton.setIcon(ImageCache.getInstance().getImage(ImageCache.CONNECT));
_connectDbButton.addActionListener(e -> {
openDatabase();
});
_disconnectDbButton.setVerticalTextPosition(SwingConstants.BOTTOM);
_disconnectDbButton.setHorizontalTextPosition(SwingConstants.CENTER);
_disconnectDbButton.setText(DISCONNECT);
_disconnectDbButton.setToolTipText(DISCONNECT_TOOLTIP);
_disconnectDbButton.setPreferredSize(preferredToolbarButtonSize);
_disconnectDbButton.setIcon(ImageCache.getInstance().getImage(ImageCache.DISCONNECT));
_disconnectDbButton.addActionListener(e -> {
try {
closeCurrentDb();
} catch (Exception e1) {
logger.error("ERROR", e1);
}
});
_historyButton.setVerticalTextPosition(SwingConstants.BOTTOM);
_historyButton.setHorizontalTextPosition(SwingConstants.CENTER);
_historyButton.setText(SQL_HISTORY);
_historyButton.setToolTipText(SQL_HISTORY_TOOLTIP);
_historyButton.setPreferredSize(preferredToolbarButtonSize);
_historyButton.setIcon(ImageCache.getInstance().getImage(ImageCache.HISTORY_DB));
_historyButton.addActionListener(e -> {
try {
if (oldSqlCommands.size() == 0) {
JOptionPane.showMessageDialog(this, "No history available.");
return;
}
String[] sqlHistory = oldSqlCommands.toArray(new String[0]);
String selected = GuiUtilities.showComboDialog(this, "HISTORY", "", sqlHistory);
if (selected != null) {
addTextToQueryEditor(selected);
}
} catch (Exception e1) {
logger.error("ERROR", e1);
}
});
_templatesButton.setVerticalTextPosition(SwingConstants.BOTTOM);
_templatesButton.setHorizontalTextPosition(SwingConstants.CENTER);
_templatesButton.setText(SQL_TEMPLATES);
_templatesButton.setToolTipText(SQL_TEMPLATES_TOOLTIP);
_templatesButton.setPreferredSize(preferredToolbarButtonSize);
_templatesButton.setIcon(ImageCache.getInstance().getImage(ImageCache.TEMPLATE));
_templatesButton.addActionListener(e -> {
try {
String[] sqlHistory = SqlTemplatesAndActions.templatesMap.keySet().toArray(new String[0]);
String selected = GuiUtilities.showComboDialog(this, "HISTORY", "", sqlHistory);
if (selected != null) {
String sql = SqlTemplatesAndActions.templatesMap.get(selected);
addTextToQueryEditor(sql);
}
} catch (Exception e1) {
logger.error("ERROR", e1);
}
});
addComponentListener(new ComponentListener(){
public void componentShown( ComponentEvent e ) {
}
public void componentResized( ComponentEvent e ) {
}
public void componentMoved( ComponentEvent e ) {
}
public void componentHidden( ComponentEvent e ) {
onClose();
}
});
try {
_databaseTreeView.setMinimumSize(new Dimension(300, 200));
addJtreeDragNDrop();
addJtreeContextMenu();
_databaseTree.setCellRenderer(new DefaultTreeCellRenderer(){
@Override
public java.awt.Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected,
boolean expanded, boolean leaf, int row, boolean hasFocus ) {
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if (value instanceof DbLevel) {
setIcon(ImageCache.getInstance().getImage(ImageCache.DATABASE));
} else if (value instanceof TypeLevel) {
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE_FOLDER));
} else if (value instanceof TableLevel) {
TableLevel tableLevel = (TableLevel) value;
if (tableLevel.isGeo) {
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE_SPATIAL));
} else {
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE));
}
} else if (value instanceof ColumnLevel) {
ColumnLevel columnLevel = (ColumnLevel) value;
if (columnLevel.isPK) {
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE_COLUMN_PRIMARYKEY));
} else if (columnLevel.references != null) {
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE_COLUMN_INDEX));
} else if (columnLevel.geomColumn != null) {
SpatialiteGeometryType gType = SpatialiteGeometryType.forValue(columnLevel.geomColumn.geometry_type);
switch( gType ) {
case POINT_XY:
case POINT_XYM:
case POINT_XYZ:
case POINT_XYZM:
case MULTIPOINT_XY:
case MULTIPOINT_XYM:
case MULTIPOINT_XYZ:
case MULTIPOINT_XYZM:
setIcon(ImageCache.getInstance().getImage(ImageCache.GEOM_POINT));
break;
case LINESTRING_XY:
case LINESTRING_XYM:
case LINESTRING_XYZ:
case LINESTRING_XYZM:
case MULTILINESTRING_XY:
case MULTILINESTRING_XYM:
case MULTILINESTRING_XYZ:
case MULTILINESTRING_XYZM:
setIcon(ImageCache.getInstance().getImage(ImageCache.GEOM_LINE));
break;
case POLYGON_XY:
case POLYGON_XYM:
case POLYGON_XYZ:
case POLYGON_XYZM:
case MULTIPOLYGON_XY:
case MULTIPOLYGON_XYM:
case MULTIPOLYGON_XYZ:
case MULTIPOLYGON_XYZM:
setIcon(ImageCache.getInstance().getImage(ImageCache.GEOM_POLYGON));
break;
default:
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE_COLUMN));
break;
}
} else {
setIcon(ImageCache.getInstance().getImage(ImageCache.TABLE_COLUMN));
}
}
return this;
}
});
_databaseTree.addTreeSelectionListener(new TreeSelectionListener(){
public void valueChanged( TreeSelectionEvent evt ) {
TreePath[] paths = evt.getPaths();
currentSelectedDb = null;
currentSelectedTable = null;
currentSelectedColumn = null;
if (paths.length > 0) {
Object selectedItem = paths[0].getLastPathComponent();
if (selectedItem instanceof DbLevel) {
currentSelectedDb = (DbLevel) selectedItem;
}
if (selectedItem instanceof TableLevel) {
currentSelectedTable = (TableLevel) selectedItem;
try {
QueryResult queryResult = currentConnectedDatabase
.getTableRecordsMapIn(currentSelectedTable.tableName, null, true, 20, -1);
loadDataViewer(queryResult);
} catch (Exception e) {
e.printStackTrace();
}
} else {
currentSelectedTable = null;
_dataViewerTable.setModel(new DefaultTableModel());
}
if (selectedItem instanceof ColumnLevel) {
currentSelectedColumn = (ColumnLevel) selectedItem;
}
}
}
});
_databaseTree.setVisible(false);
} catch (Exception e1) {
JGTLogger.logError(this, "Error", e1);
}
layoutTree(null, false);
_runQueryButton.setIcon(ImageCache.getInstance().getImage(ImageCache.RUN));
_runQueryButton.setToolTipText(RUN_QUERY_TOOLTIP);
_runQueryButton.setText("");
_runQueryButton.setPreferredSize(preferredSqleditorButtonSize);
_runQueryButton.addActionListener(e -> {
String sqlText = _sqlEditorArea.getText().trim();
if (sqlText.length() == 0) {
return;
}
final LogConsoleController logConsole = new LogConsoleController(pm);
JFrame window = guiBridge.showWindow(logConsole.asJComponent(), "Console Log");
new Thread(() -> {
boolean hadErrors = false;
try {
logConsole.beginProcess("Run query");
hadErrors = runQuery(sqlText, pm);
} catch (Exception ex) {
pm.errorMessage(ex.getLocalizedMessage());
hadErrors = true;
} finally {
logConsole.finishProcess();
logConsole.stopLogging();
if (!hadErrors) {
logConsole.setVisible(false);
window.dispose();
}
}
}).start();
});
_runQueryAndStoreButton.setIcon(ImageCache.getInstance().getImage(ImageCache.RUN_TO_FILE));
_runQueryAndStoreButton.setToolTipText(RUN_QUERY_TO_FILE_TOOLTIP);
_runQueryAndStoreButton.setText("");
_runQueryAndStoreButton.setPreferredSize(preferredSqleditorButtonSize);
_runQueryAndStoreButton.addActionListener(e -> {
File selectedFile = null;
String sqlText = _sqlEditorArea.getText().trim();
if (sqlText.length() > 0) {
if (isSelectOrPragma(sqlText)) {
File[] saveFiles = guiBridge.showSaveFileDialog("Select file to save to", GuiUtilities.getLastFile());
if (saveFiles != null && saveFiles.length > 0) {
try {
GuiUtilities.setLastPath(saveFiles[0].getAbsolutePath());
} catch (Exception e1) {
logger.error("ERROR", e1);
}
} else {
return;
}
selectedFile = saveFiles[0];
} else {
JOptionPane.showMessageDialog(this, "Writing to files is allowed only for SELECT statements and PRAGMAs.",
"WARNING", JOptionPane.WARNING_MESSAGE, null);
return;
}
}
final LogConsoleController logConsole = new LogConsoleController(pm);
JFrame window = guiBridge.showWindow(logConsole.asJComponent(), "Console Log");
final File f_selectedFile = selectedFile;
new Thread(() -> {
boolean hadErrors = false;
try {
if (f_selectedFile != null) {
logConsole.beginProcess("Run query");
hadErrors = runQueryToFile(sqlText, f_selectedFile, pm);
}
} catch (Exception ex) {
pm.errorMessage(ex.getLocalizedMessage());
hadErrors = true;
} finally {
logConsole.finishProcess();
logConsole.stopLogging();
if (!hadErrors) {
logConsole.setVisible(false);
window.dispose();
}
}
}).start();
});
_runQueryAndStoreShapefileButton.setIcon(ImageCache.getInstance().getImage(ImageCache.RUN_TO_SHAPEFILE));
_runQueryAndStoreShapefileButton.setToolTipText(RUN_QUERY_TO_SHAPEFILE_TOOLTIP);
_runQueryAndStoreShapefileButton.setText("");
_runQueryAndStoreShapefileButton.setPreferredSize(preferredSqleditorButtonSize);
_runQueryAndStoreShapefileButton.addActionListener(e -> {
File selectedFile = null;
String sqlText = _sqlEditorArea.getText().trim();
if (sqlText.length() > 0) {
if (sqlText.toLowerCase().startsWith("select")) {
File[] saveFiles = guiBridge.showSaveFileDialog("Select shapefile to save to", GuiUtilities.getLastFile());
if (saveFiles != null && saveFiles.length > 0) {
try {
GuiUtilities.setLastPath(saveFiles[0].getAbsolutePath());
} catch (Exception e1) {
logger.error("ERROR", e1);
}
} else {
return;
}
selectedFile = saveFiles[0];
} else {
JOptionPane.showMessageDialog(this, "Writing to shapefile is allowed only for SELECT statements.", "WARNING",
JOptionPane.WARNING_MESSAGE, null);
return;
}
}
final LogConsoleController logConsole = new LogConsoleController(pm);
JFrame window = guiBridge.showWindow(logConsole.asJComponent(), "Console Log");
final File f_selectedFile = selectedFile;
new Thread(() -> {
boolean hadErrors = false;
try {
if (f_selectedFile != null) {
logConsole.beginProcess("Run query");
hadErrors = runQueryToShapefile(sqlText, f_selectedFile, pm);
}
} catch (Exception ex) {
pm.errorMessage(ex.getLocalizedMessage());
hadErrors = true;
} finally {
logConsole.finishProcess();
logConsole.stopLogging();
if (!hadErrors) {
logConsole.setVisible(false);
window.dispose();
}
}
}).start();
});
setViewQueryButton(_viewQueryButton, preferredSqleditorButtonSize, _sqlEditorArea);
_clearSqlEditorbutton.setIcon(ImageCache.getInstance().getImage(ImageCache.TRASH));
_clearSqlEditorbutton.setToolTipText(CLEAR_SQL_EDITOR);
_clearSqlEditorbutton.setText("");
_clearSqlEditorbutton.setPreferredSize(preferredSqleditorButtonSize);
_clearSqlEditorbutton.addActionListener(e -> {
_sqlEditorArea.setText("");
});
}
protected abstract void setViewQueryButton( JButton _viewQueryButton, Dimension preferredButtonSize,
JTextPane sqlEditorArea );
private void addJtreeDragNDrop() {
_databaseTree.setDragEnabled(true);
_databaseTree.setTransferHandler(new TransferHandler(null){
public int getSourceActions( JComponent c ) {
return COPY;
}
protected Transferable createTransferable( JComponent c ) {
if (c instanceof JTree) {
if (currentSelectedColumn != null) {
return new StringSelection(currentSelectedColumn.columnName);
} else if (currentSelectedTable != null) {
return new StringSelection(currentSelectedTable.tableName);
}
}
return new StringSelection("");
}
});
}
private void addJtreeContextMenu() {
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new BevelBorder(BevelBorder.RAISED));
popupMenu.addPopupMenuListener(new PopupMenuListener(){
@Override
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
if (currentSelectedTable != null) {
List tableActions = makeTableAction(currentSelectedTable);
for( Action action : tableActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
} else if (currentSelectedDb != null) {
List tableActions = makeDatabaseAction(currentSelectedDb);
for( Action action : tableActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
} else if (currentSelectedColumn != null) {
List columnActions = makeColumnActions(currentSelectedColumn);
for( Action action : columnActions ) {
if (action != null) {
JMenuItem item = new JMenuItem(action);
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
} else {
popupMenu.add(new JSeparator());
}
}
}
}
@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
popupMenu.removeAll();
}
@Override
public void popupMenuCanceled( PopupMenuEvent e ) {
popupMenu.removeAll();
}
});
_databaseTree.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked( MouseEvent e ) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = _databaseTree.getClosestRowForLocation(e.getX(), e.getY());
_databaseTree.setSelectionRow(row);
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
private void addDataTableContextMenu() {
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new BevelBorder(BevelBorder.RAISED));
popupMenu.addPopupMenuListener(new PopupMenuListener(){
@Override
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
JMenuItem item = new JMenuItem(new AbstractAction("Copy cells content"){
@Override
public void actionPerformed( ActionEvent e ) {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
_dataViewerTable.getTransferHandler().exportToClipboard(_dataViewerTable, clipboard,
TransferHandler.COPY);
}
});
popupMenu.add(item);
item.setHorizontalTextPosition(JMenuItem.RIGHT);
}
@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
popupMenu.removeAll();
}
@Override
public void popupMenuCanceled( PopupMenuEvent e ) {
popupMenu.removeAll();
}
});
_dataViewerTable.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked( MouseEvent e ) {
if (SwingUtilities.isRightMouseButton(e)) {
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
protected void loadDataViewer( QueryResult queryResult ) {
if (queryResult == null) {
_dataViewerTable.setModel(new DefaultTableModel());
return;
}
Object[] names = queryResult.names.toArray(new String[0]);
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy