TreeDatabase.java
package com.jsql.view.swing.tree;
import com.jsql.model.bean.database.AbstractElementDatabase;
import com.jsql.model.bean.database.Column;
import com.jsql.model.bean.database.Database;
import com.jsql.model.bean.database.Table;
import com.jsql.util.LogLevelUtil;
import com.jsql.view.swing.tree.model.AbstractNodeModel;
import com.jsql.view.swing.tree.model.NodeModelColumn;
import com.jsql.view.swing.tree.model.NodeModelDatabase;
import com.jsql.view.swing.tree.model.NodeModelTable;
import com.jsql.view.swing.util.MediatorHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TreeDatabase extends JTree {
/**
* Log4j logger sent to view.
*/
private static final Logger LOGGER = LogManager.getRootLogger();
/**
* Map a database element with the corresponding tree node.<br>
* The injection model send a database element to the view, then
* the view access its graphic component to update.
*/
private final transient Map<AbstractElementDatabase, DefaultMutableTreeNode> mapNodes = new HashMap<>();
public TreeDatabase(DefaultMutableTreeNode root) {
super(root);
}
public void reloadNodes() {
// I18n of tree empty node
if (this.isRootVisible()) {
DefaultTreeModel model = (DefaultTreeModel) this.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
model.reload(root);
this.revalidate();
}
}
public void reset() {
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model for refreshing the tree
DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot(); // The tree root
root.removeAllChildren(); // Remove tree nodes
treeModel.nodeChanged(root); // Refresh the root
treeModel.reload(); // Refresh the tree
this.setRootVisible(true);
}
public void addColumns(List<Column> columns) {
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model, update the tree (refresh, add node, etc.)
DefaultMutableTreeNode tableNode = null; // The table to update
// Loop into the list of columns
for (Column column: columns) {
AbstractNodeModel newTreeNodeModel = new NodeModelColumn(column); // Create a node model with the column element
var newNode = new DefaultMutableTreeNode(newTreeNodeModel); // Create the node
tableNode = this.getTreeNodeModels().get(column.getParent()); // Get the parent table
// Fix #1805 : NullPointerException on tableNode.getChildCount()
if (tableNode != null) {
treeModel.insertNodeInto(newNode, tableNode, tableNode.getChildCount()); // Add the column to the table
}
}
if (tableNode != null) {
this.expandPath(new TreePath(tableNode.getPath())); // Open the table node
((AbstractNodeModel) tableNode.getUserObject()).setLoaded(true); // The table has just been search (avoid double check)
}
}
public void addDatabases(List<Database> databases) {
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model, update the tree (refresh, add node, etc.)
DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot(); // First node in tree
// Loop into the list of databases
for (Database database: databases) {
AbstractNodeModel newTreeNodeModel = new NodeModelDatabase(database); // Create a node model with the database element
var newNode = new DefaultMutableTreeNode(newTreeNodeModel); // Create the node
this.getTreeNodeModels().put(database, newNode); // Save the node
root.add(newNode); // Add the node to the tree
}
// Refresh the tree
treeModel.reload(root);
// Open the root node
this.expandPath(new TreePath(root.getPath()));
this.setRootVisible(false);
}
public void addTables(List<Table> tables) {
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model, update the tree (refresh, add node, etc.)
DefaultMutableTreeNode databaseNode = null; // The database to update
// Loop into the list of tables
for (Table table: tables) {
AbstractNodeModel newTreeNodeModel = new NodeModelTable(table); // Create a node model with the table element
var newNode = new DefaultMutableTreeNode(newTreeNodeModel); // Create the node
this.getTreeNodeModels().put(table, newNode); // Save the node
databaseNode = this.getTreeNodeModels().get(table.getParent()); // Get the parent database
// Report NullPointerException #1670
if (databaseNode != null) {
treeModel.insertNodeInto(newNode, databaseNode, databaseNode.getChildCount()); // Add the table to the database
} else {
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Missing database for table {}.", () -> table);
}
}
if (databaseNode != null) {
this.expandPath(new TreePath(databaseNode.getPath())); // Open the database node
((AbstractNodeModel) databaseNode.getUserObject()).setLoaded(true); // The database has just been search (avoid double check)
}
}
public void createValuesTab(String[][] data, String[] columnNames, AbstractElementDatabase table) {
// Report NullPointerException #1683
DefaultMutableTreeNode node = this.getTreeNodeModels().get(table);
if (node != null) {
AbstractNodeModel progressingTreeNodeModel = (AbstractNodeModel) node.getUserObject(); // Get the node
progressingTreeNodeModel.setIndexProgress(table.getChildCount()); // Update the progress value of the model, end the progress
progressingTreeNodeModel.setRunning(false); // Mark the node model as 'no stop/pause/resume button'
MediatorHelper.tabResults().createValuesTab(data, columnNames, table);
}
}
public void endIndeterminateProgress(AbstractElementDatabase dataElementDatabase) {
// Tree model, update the tree (refresh, add node, etc.)
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel();
DefaultMutableTreeNode nodeModel = this.getTreeNodeModels().get(dataElementDatabase);
// Fix #1806 : NullPointerException on ...odels().get(dataElementDatabase).getUserObject()
if (nodeModel != null) {
AbstractNodeModel progressingTreeNodeModel = (AbstractNodeModel) nodeModel.getUserObject(); // Get the node
progressingTreeNodeModel.setProgressing(false); // Mark the node model as 'no loading bar'
progressingTreeNodeModel.setRunning(false); // Mark the node model as 'no stop/pause/resume button'
treeModel.nodeChanged(nodeModel); // Update the node
}
}
public void endProgress(AbstractElementDatabase dataElementDatabase) {
// Tree model, update the tree (refresh, add node, etc.)
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel();
// Report NullPointerException #1671
DefaultMutableTreeNode node = this.getTreeNodeModels().get(dataElementDatabase);
if (node != null) {
AbstractNodeModel progressingTreeNodeModel = (AbstractNodeModel) node.getUserObject(); // Get the node
progressingTreeNodeModel.setLoading(false); // Mark the node model as 'no progress bar'
progressingTreeNodeModel.setRunning(false); // Mark the node model as 'no stop/pause/resume button'
progressingTreeNodeModel.setIndexProgress(0); // Reset the progress value of the model
treeModel.nodeChanged(node); // Update the node and progress bar
}
}
public void startIndeterminateProgress(AbstractElementDatabase dataElementDatabase) {
DefaultMutableTreeNode node = this.getTreeNodeModels().get(dataElementDatabase);
// Fix #45540: NullPointerException on node.getUserObject()
if (node != null) {
AbstractNodeModel progressingTreeNodeModel = (AbstractNodeModel) node.getUserObject(); // Get the node
progressingTreeNodeModel.setProgressing(true); // Mark the node model as 'loading'
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model, update the tree (refresh, add node, etc.)
treeModel.nodeChanged(node); // Update the node
}
}
public void startProgress(AbstractElementDatabase dataElementDatabase) {
DefaultMutableTreeNode node = this.getTreeNodeModels().get(dataElementDatabase);
// Fix rare #73981
if (node != null) {
AbstractNodeModel progressingTreeNodeModel = (AbstractNodeModel) node.getUserObject(); // Get the node
// Fix rare Unhandled NullPointerException #66340
if (progressingTreeNodeModel != null) {
progressingTreeNodeModel.setLoading(true); // Mark the node model as 'display progress bar'
}
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model, update the tree (refresh, add node, etc.)
treeModel.nodeChanged(node); // Update the node
}
}
public void updateProgress(AbstractElementDatabase dataElementDatabase, int dataCount) {
DefaultMutableTreeNode node = this.getTreeNodeModels().get(dataElementDatabase);
// Fix Report #1368: ignore if no element database, usually for mock (eg. metadata, file, shell, list databases)
if (node != null) {
AbstractNodeModel progressingTreeNodeModel = (AbstractNodeModel) node.getUserObject(); // Get the node
progressingTreeNodeModel.setIndexProgress(dataCount); // Update the progress value of the model
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel(); // Tree model, update the tree (refresh, add node, etc.)
treeModel.nodeChanged(node); // Update the node
}
}
public final Map<AbstractElementDatabase, DefaultMutableTreeNode> getTreeNodeModels() {
return this.mapNodes;
}
}