import/Export of connections and models, first steps

This commit is contained in:
Ralf Wisser
2023-11-17 12:10:03 +01:00
parent d9b82686d6
commit a286bef4a6
6 changed files with 225 additions and 123 deletions
@@ -234,6 +234,8 @@ public class Configuration {
File configFile;
if (applicationBase == null) {
configFile = new File(name);
// TODO
// TODO if .multi/.singleuser -> look in users home
} else {
configFile = new File(applicationBase, name);
}
@@ -1996,9 +1996,3 @@ public class DbConnectionDetailsEditor extends javax.swing.JDialog {
private static final long serialVersionUID = -492511696901313920L;
}
// TODO
// TODO new csv-based load-method should use "DataModel-displayNName" as fallback (bco. externally generated "connections.csv")
@@ -83,6 +83,7 @@ import net.sf.jailer.ui.util.UISettings;
import net.sf.jailer.util.ClasspathUtil;
import net.sf.jailer.util.CsvFile;
import net.sf.jailer.util.CsvFile.Line;
import net.sf.jailer.util.LogUtil;
import net.sf.jailer.util.Pair;
/**
@@ -405,7 +406,6 @@ public class DbConnectionDialog extends javax.swing.JDialog {
private final boolean dataModelAware;
private final DataModelChanger dataModelChanger;
// TODO
// TODO remove, no longer used
private final boolean showOnlyRecentyUsedConnections;
@@ -771,20 +771,10 @@ public class DbConnectionDialog extends javax.swing.JDialog {
return;
}
try {
for (ConnectionInfo ci: connectionList) {
ci.encrypt();
}
File file = Environment.newFile(CONNECTIONS_FILE);
saveAsCSV(connectionList, file);
File file = Environment.newFile(CONNECTIONS_FILE_LEGACY);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file)); // lgtm [java/output-resource-leak]
out.writeObject(connectionList);
out.writeInt(connectionList.indexOf(currentConnection));
List<String> dataModels = new ArrayList<String>();
for (ConnectionInfo ci: connectionList) {
dataModels.add(ci.dataModelFolder);
}
out.writeObject(dataModels);
out.close();
Environment.newFile(CONNECTIONS_FILE_LEGACY).renameTo(Environment.newFile(CONNECTIONS_FILE_LEGACY + ".obsolete"));
if (!onConnectionListChangedPending) {
onConnectionListChangedPending = true;
@@ -797,11 +787,7 @@ public class DbConnectionDialog extends javax.swing.JDialog {
}
} catch (Exception e) {
e.printStackTrace();
} finally {
for (ConnectionInfo ci: connectionList) {
ci.decrypt();
}
LogUtil.warn(e);
}
}
@@ -835,51 +821,55 @@ public class DbConnectionDialog extends javax.swing.JDialog {
ConnectionInfo oldCurrentConnection = currentConnection;
currentConnection = null;
boolean ok = false;
boolean preV4 = true;
try {
File file = Environment.newFile(CONNECTIONS_FILE_LEGACY);
File file = Environment.newFile(CONNECTIONS_FILE);
if (file.exists()) {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); // lgtm [java/input-resource-leak]
List<ConnectionInfo> cis = (List<ConnectionInfo>) in.readObject();
int i = in.readInt();
boolean isEncrypted = true;
try {
List<String> dma = (List<String>) in.readObject();
for (int n = 0; n < dma.size(); ++n) {
ConnectionInfo connectionInfo = cis.get(n);
if (!connectionInfo.decrypt()) {
isEncrypted = false;
}
connectionInfo.dataModelFolder = dma.get(n);
if (connectionInfo.jar1 == null) {
connectionInfo.jar1 = "";
}
if (connectionInfo.jar2 == null) {
connectionInfo.jar2 = "";
}
if (connectionInfo.jar3 == null) {
connectionInfo.jar3 = "";
}
if (connectionInfo.jar4 == null) {
connectionInfo.jar4 = "";
}
connectionInfo.jar1 = UIUtil.correctFileSeparator(connectionInfo.jar1);
connectionInfo.jar2 = UIUtil.correctFileSeparator(connectionInfo.jar2);
connectionInfo.jar3 = UIUtil.correctFileSeparator(connectionInfo.jar3);
connectionInfo.jar4 = UIUtil.correctFileSeparator(connectionInfo.jar4);
}
preV4 = false;
} catch (Throwable t) {
// ignore. pre 4.0 files do not contain data model assignments.
}
in.close();
connectionList = cis;
if (!isEncrypted) {
// The access data is not yet encrypted. Save it in encrypted form.
store();
}
connectionList = loadAsCSV(file);
ok = true;
} else {
file = Environment.newFile(CONNECTIONS_FILE_LEGACY);
if (file.exists()) {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); // lgtm [java/input-resource-leak]
List<ConnectionInfo> cis = (List<ConnectionInfo>) in.readObject();
int i = in.readInt();
boolean isEncrypted = true;
try {
List<String> dma = (List<String>) in.readObject();
for (int n = 0; n < dma.size(); ++n) {
ConnectionInfo connectionInfo = cis.get(n);
if (!connectionInfo.decrypt()) {
isEncrypted = false;
}
connectionInfo.dataModelFolder = dma.get(n);
if (connectionInfo.jar1 == null) {
connectionInfo.jar1 = "";
}
if (connectionInfo.jar2 == null) {
connectionInfo.jar2 = "";
}
if (connectionInfo.jar3 == null) {
connectionInfo.jar3 = "";
}
if (connectionInfo.jar4 == null) {
connectionInfo.jar4 = "";
}
connectionInfo.jar1 = UIUtil.correctFileSeparator(connectionInfo.jar1);
connectionInfo.jar2 = UIUtil.correctFileSeparator(connectionInfo.jar2);
connectionInfo.jar3 = UIUtil.correctFileSeparator(connectionInfo.jar3);
connectionInfo.jar4 = UIUtil.correctFileSeparator(connectionInfo.jar4);
}
} catch (Throwable t) {
// ignore. pre 4.0 files do not contain data model assignments.
}
in.close();
connectionList = cis;
if (!isEncrypted) {
// The access data is not yet encrypted. Save it in encrypted form.
store();
}
ok = true;
}
}
} catch (Exception e) {
e.printStackTrace();
@@ -923,10 +913,8 @@ public class DbConnectionDialog extends javax.swing.JDialog {
ci.password = "";
ci.dataModelFolder = "Demo-Scott";
connectionList.add(ci);
store();
}
if (preV4) {
ConnectionInfo ci = new ConnectionInfo(executionContext);
ci = new ConnectionInfo(executionContext);
ci.alias = "Demo Sakila";
ci.driverClass = "org.h2.Driver";
ci.jar1 = "lib" + File.separator + "h2-2.1.212.jar";
@@ -1395,7 +1383,7 @@ public class DbConnectionDialog extends javax.swing.JDialog {
}//GEN-LAST:event_restoreLastSessionButtonActionPerformed
public void importConnections(Window owner) {
Pair<Boolean, Pair<Integer, List<ConnectionInfo>>> result = ExportPanel.doImport(owner, this);
Pair<Boolean, Pair<Integer, List<ConnectionInfo>>> result = ExportPanel.openImportDialog(owner, this);
if (result.a) {
if (result.b.a > 0) {
notifyDataModelsChanged();
@@ -1799,13 +1787,13 @@ public class DbConnectionDialog extends javax.swing.JDialog {
writer.append("# Passwords and URLs starting with '" + OBFUSCATED_MARKER_PREFIX + "' are encrypted." + UIUtil.LINE_SEPARATOR);
writer.append("# You may use non-encrypted text here by omitting the prefix." + UIUtil.LINE_SEPARATOR);
writer.append(UIUtil.LINE_SEPARATOR);
writer.append("# Name; User; URL; Data model folder; Connection type (Development/Test/Staging/Production or empty); Password; Driver class; Driver JAR; additional JAR 1; additional JAR 2; additional JAR 3; additional JAR 4;" + UIUtil.LINE_SEPARATOR);
writer.append("# Name; User; Data model folder; Connection type (Development/Test/Staging/Production or empty); URL; Password; Driver class; Driver JAR; additional JAR 1; additional JAR 2; additional JAR 3; additional JAR 4;" + UIUtil.LINE_SEPARATOR);
for (ConnectionInfo ci: infos) {
writer.append(CsvFile.encodeCell(ci.alias) + "; ");
writer.append(CsvFile.encodeCell(ci.user) + "; ");
writer.append(OBFUSCATED_MARKER_PREFIX + CsvFile.encodeCell(stringObfuscator.encrypt(ci.url)) + "; ");
writer.append(CsvFile.encodeCell(ci.dataModelFolder) + "; ");
writer.append(CsvFile.encodeCell(ci.getConnectionType().name()) + "; ");
writer.append(OBFUSCATED_MARKER_PREFIX + CsvFile.encodeCell(stringObfuscator.encrypt(ci.url)) + "; ");
writer.append(OBFUSCATED_MARKER_PREFIX + CsvFile.encodeCell(stringObfuscator.encrypt(ci.password)) + "; ");
writer.append(CsvFile.encodeCell(ci.driverClass) + "; ");
writer.append(CsvFile.encodeCell(ci.jar1) + "; ");
@@ -1821,16 +1809,16 @@ public class DbConnectionDialog extends javax.swing.JDialog {
List<ConnectionInfo> list = new ArrayList<>();
CsvFile csvFile = new CsvFile(file);
for (Line line: csvFile.getLines()) {
if (!line.cells.get(0).isEmpty()) {
if (!line.cells.get(0).isEmpty() && !line.cells.get(0).matches("^\"#.*\"$")) {
ConnectionInfo ci = new ConnectionInfo();
ci.alias = line.cells.get(0);
ci.user = line.cells.get(1);
ci.url = line.cells.get(2);
ci.dataModelFolder = line.cells.get(2);
ci.connectionTypeName = line.cells.get(3);
ci.url = line.cells.get(4);
if (ci.url.startsWith(OBFUSCATED_MARKER_PREFIX)) {
ci.url = stringObfuscator.decrypt(ci.url.substring(OBFUSCATED_MARKER_PREFIX.length()));
}
ci.dataModelFolder = line.cells.get(3);
ci.connectionTypeName = line.cells.get(4);
ci.password = line.cells.get(5);
if (ci.password.startsWith(OBFUSCATED_MARKER_PREFIX)) {
ci.password = stringObfuscator.decrypt(ci.password.substring(OBFUSCATED_MARKER_PREFIX.length()));
@@ -1849,16 +1837,6 @@ public class DbConnectionDialog extends javax.swing.JDialog {
}
// TODO
// TODO import/export of sets of connections
// TODO use csv for connection definition storage. Header (comment) line. "plain/obfuscated password (y/n)"; + password column.
// TODO
// TODO "jailer.xml" should be editable for everyone, including state 1000+.
// TODO
// TODO document new csv-format for connectios.csv
// TODO 1
// TODO programmatic SLL certificate import?
// TODO https://stackoverflow.com/questions/18889058/programmatically-import-ca-trust-cert-into-existing-keystore-file-without-using
@@ -136,6 +136,8 @@ public class Environment {
copyIfNotExists("demo-scott-subset.mv.db");
copyIfNotExists("example");
copyIfNotExists("render");
// TODO
// TODO jailer.xml
if (isJPacked()) {
File lib = newFile("lib");
+160 -34
View File
@@ -21,9 +21,12 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -46,16 +49,34 @@ import javax.swing.WindowConstants;
import org.fife.rsta.ui.EscapableDialog;
/*
* Copyright 2007 - 2023 Ralf Wisser.
*
* Licensed 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
*
* http://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.
*/
import net.sf.jailer.ExecutionContext;
import net.sf.jailer.configuration.Configuration;
import net.sf.jailer.ui.DbConnectionDialog.ConnectionInfo;
import net.sf.jailer.ui.Environment.CopyFileVisitor;
import net.sf.jailer.ui.UIUtil.PLAF;
import net.sf.jailer.ui.util.CompoundIcon;
import net.sf.jailer.util.LogUtil;
import net.sf.jailer.util.Pair;
/**
* UI for exporting data models and database connections.
*
* @author RalfW
* @author Ralf Wisser
*/
public class ExportPanel extends javax.swing.JPanel {
@@ -82,6 +103,11 @@ public class ExportPanel extends javax.swing.JPanel {
private ExecutionContext executionContext;
public boolean openExportDialog(Window owner, Object initiallySelected, DbConnectionDialog connectionDialog) {
List<ConnectionInfo> connectionList = connectionDialog.getConnectionList();
return openDialog(owner, initiallySelected, connectionList, new HashSet<>(), "Export data models and connections", connectionDialog);
}
private boolean openDialog(Window owner, Object initiallySelected, List<ConnectionInfo> connectionList, Set<String> tabuModels, String title, DbConnectionDialog connectionDialog) {
executionContext = connectionDialog.executionContext;
dialog = owner instanceof Dialog? new EscapableDialog((Dialog) owner) {
} : new EscapableDialog((Frame) owner) {
@@ -89,11 +115,10 @@ public class ExportPanel extends javax.swing.JPanel {
dialog.getContentPane().add(this);
dialog.setModal(true);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.setTitle("Export data models and connections");
dialog.setTitle(title);
dialog.pack();
dialog.setSize(Math.max(500, dialog.getWidth()), Math.min(700, Math.max(500, dialog.getHeight())));
// TODO
// TODO check size bounds
UIUtil.fit(dialog);
dialog.setLocation(owner.getX() + owner.getWidth() / 2 - dialog.getWidth() / 2, owner.getY() + owner.getHeight() / 2 - dialog.getHeight() / 2);
@@ -115,7 +140,7 @@ public class ExportPanel extends javax.swing.JPanel {
}
int y = 1;
List<ConnectionInfo> connections = new ArrayList<>(connectionDialog.getConnectionList());
List<ConnectionInfo> connections = new ArrayList<>(connectionList);
connections.sort((a, b) -> a.alias.compareToIgnoreCase(b.alias));
List<ConnectionInfo> rest = new ArrayList<>(connections);
List<Entry<String, String>> entryList = new ArrayList<>(modelNames.entrySet());
@@ -135,28 +160,32 @@ public class ExportPanel extends javax.swing.JPanel {
String value = entry == null? orphaned : entry.getValue();
JCheckBox jCheckBox = new JCheckBox();
if (entry != null) {
checkBoxes.add(jCheckBox);
jCheckBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (jCheckBox.isSelected()) {
selectedModels.add(key);
} else {
selectedModels.remove(key);
if (!tabuModels.contains(key)) {
checkBoxes.add(jCheckBox);
if (key.equals(initiallySelected) || Boolean.TRUE.equals(initiallySelected)) {
selectAndScrollTo(jCheckBox);
}
jCheckBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (jCheckBox.isSelected()) {
selectedModels.add(key);
} else {
selectedModels.remove(key);
}
updateStatus();
}
updateStatus();
}
});
});
} else {
jCheckBox.setEnabled(false);
}
jCheckBox.setText(" ");
jCheckBox.setFocusable(false);
GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = y;
gridBagConstraints.insets = new Insets(b, 0, b, 0);
selectionPanel.add(jCheckBox, gridBagConstraints);
if (key.equals(initiallySelected)) {
selectAndScrollTo(jCheckBox);
}
GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = y;
gridBagConstraints.insets = new Insets(b, 0, b, 0);
selectionPanel.add(jCheckBox, gridBagConstraints);
}
JLabel label = new JLabel();
@@ -204,7 +233,7 @@ public class ExportPanel extends javax.swing.JPanel {
updateStatus();
}
});
if (ci.equals(initiallySelected)) {
if (ci.equals(initiallySelected) || Boolean.TRUE.equals(initiallySelected)) {
selectAndScrollTo(jCheckBox2);
}
gridBagConstraints = new java.awt.GridBagConstraints();
@@ -439,7 +468,7 @@ public class ExportPanel extends javax.swing.JPanel {
dialog.dispose();
}//GEN-LAST:event_okButtonActionPerformed
private void doExport() {
protected void doExport() {
String cmsf = DataModelManager.getCurrentModelSubfolder(executionContext);
try {
DataModelManager.setCurrentModelSubfolder(null, executionContext);
@@ -467,14 +496,100 @@ public class ExportPanel extends javax.swing.JPanel {
}
}
public static Pair<Boolean, Pair<Integer, List<ConnectionInfo>>> doImport(Window owner, DbConnectionDialog connectionDialog) {
public static Pair<Boolean, Pair<Integer, List<ConnectionInfo>>> openImportDialog(Window owner, DbConnectionDialog connectionDialog) {
ExecutionContext executionContext = connectionDialog.executionContext;
String oldDatamodelFolder = executionContext.getDatamodelFolder();
File tmpFile = null;
try {
tmpFile = Configuration.getInstance().createTempFile();
executionContext.setDatamodelFolder(tmpFile.getPath());
Path targetPath = tmpFile.toPath();
String file = UIUtil.choseFile(null, ".", "Import data models and connections", ".zip", owner, true, true);
if (file != null) {
Pair<Boolean, Pair<Integer, List<ConnectionInfo>>> importTmp = doImport(owner, file, true, null, null, connectionDialog);
Set<String> tabuModels = new HashSet<>();
if (importTmp.a) {
List<ConnectionInfo> connectionList = importTmp.b.b;
Path start = Paths.get(oldDatamodelFolder);
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
private Path sourcePath = null;
@Override
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
if (!dir.equals(start)) {
if (!connectionList.stream().anyMatch(ci -> dir.endsWith(ci.dataModelFolder))) {
return FileVisitResult.SKIP_SUBTREE;
}
}
if (sourcePath == null) {
sourcePath = dir;
}
Path targetDir = targetPath.resolve(sourcePath.relativize(dir));
if (!targetDir.toFile().exists()) {
tabuModels.add(dir.toFile().getName());
}
Files.createDirectories(targetDir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
try {
Path target = sourcePath == null ? targetPath : targetPath.resolve(sourcePath.relativize(file));
if (!target.toFile().exists()) {
Files.copy(file, target);
}
} catch (Exception e) {
// ignore
}
return FileVisitResult.CONTINUE;
}
});
ExportPanel exportPanel = new ExportPanel() {
@Override
protected void doExport() {
}
};
exportPanel.okButton.setText(" Import ");
if (exportPanel.openDialog(owner, true, connectionList, tabuModels, "Import data models and connections", connectionDialog)) {
return doImport(owner, file, false, exportPanel.selectedConnections, exportPanel.selectedModels, connectionDialog);
}
}
}
} catch (Exception e) {
UIUtil.showException(owner, "Error", e);
} finally {
executionContext.setDatamodelFolder(oldDatamodelFolder);
if (tmpFile != null) {
deleteDir(tmpFile);
}
}
return new Pair<Boolean, Pair<Integer, List<ConnectionInfo>>>(false, new Pair<Integer, List<ConnectionInfo>>(0, null));
}
private static void deleteDir(File file) {
try {
File[] contents = file.listFiles();
if (contents != null) {
for (File f : contents) {
deleteDir(f);
}
}
file.delete();
} catch (Throwable t) {
LogUtil.warn(t);
}
}
private static Pair<Boolean, Pair<Integer, List<ConnectionInfo>>> doImport(Window owner, String file, boolean silent, Set<ConnectionInfo> selectedConnections, Set<String> selectedModels, DbConnectionDialog connectionDialog) {
ExecutionContext executionContext = connectionDialog.executionContext;
String cmsf = DataModelManager.getCurrentModelSubfolder(executionContext);
int numModels = 0;
List<ConnectionInfo> cList = null;
try {
DataModelManager.setCurrentModelSubfolder(null, executionContext);
String file = UIUtil.choseFile(null, ".", "Import data models and connections", ".zip", owner, true, true);
UIUtil.setWaitCursor(owner);
if (file != null) {
try {
@@ -483,7 +598,8 @@ public class ExportPanel extends javax.swing.JPanel {
ZipEntry entry = zipIn.getNextEntry();
boolean ok = false;
while (entry != null) {
if (entry.getName().endsWith(EXPORT_MARKER)) {
String name2 = entry.getName();
if (name2.endsWith(EXPORT_MARKER)) {
ok = true;
}
zipIn.closeEntry();
@@ -505,8 +621,9 @@ public class ExportPanel extends javax.swing.JPanel {
Set<String> models = new HashSet<>();
// iterates over entries in the zip file
while (entry != null) {
if (!entry.getName().endsWith(EXPORT_MARKER)) {
if (entry.getName().equals(DbConnectionDialog.CONNECTIONS_FILE)) {
String name = entry.getName();
if (!name.endsWith(EXPORT_MARKER) && (selectedModels == null || selectedModels.stream().anyMatch(m -> name.startsWith(m + "/") || name.startsWith(m + "\\")))) {
if (name.equals(DbConnectionDialog.CONNECTIONS_FILE)) {
File cFile = Configuration.getInstance().createTempFile();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(cFile));
byte[] bytesIn = new byte[4096];
@@ -518,7 +635,7 @@ public class ExportPanel extends javax.swing.JPanel {
cList = DbConnectionDialog.loadAsCSV(cFile);
cFile.delete();
} else {
String filePath = executionContext.getDatamodelFolder() + File.separator + entry.getName();
String filePath = executionContext.getDatamodelFolder() + File.separator + name;
if (!entry.isDirectory()) {
// if the entry is a file, extracts it
models.add(new File(filePath).getParentFile().getName());
@@ -542,6 +659,10 @@ public class ExportPanel extends javax.swing.JPanel {
}
zipIn.close();
if (selectedConnections != null) {
cList = new ArrayList<>(selectedConnections);
}
numModels = models.size();
int numConnections = cList == null? 0 : cList.size();
@@ -556,7 +677,9 @@ public class ExportPanel extends javax.swing.JPanel {
info += numConnections + " connection" + (numConnections == 1? "" : "s");
}
info = info + " imported.";
JOptionPane.showMessageDialog(owner, info);
if (!silent) {
JOptionPane.showMessageDialog(owner, info);
}
} catch (Exception e) {
UIUtil.showException(owner, "Error", e);
return new Pair<Boolean, Pair<Integer, List<ConnectionInfo>>>(true, new Pair<Integer, List<ConnectionInfo>>(1, cList));
@@ -580,7 +703,7 @@ public class ExportPanel extends javax.swing.JPanel {
try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p))) {
for (String dm: selectedModels) {
Files.walk(dmPath.resolve(dm)).filter(path -> !Files.isDirectory(path)).forEach(path -> {
ZipEntry zipEntry = new ZipEntry(dmPath.relativize(path).toString());
ZipEntry zipEntry = new ZipEntry(dmPath.relativize(path).toString().replace(File.separatorChar, '/'));
try {
zs.putNextEntry(zipEntry);
Files.copy(path, zs);
@@ -637,3 +760,6 @@ public class ExportPanel extends javax.swing.JPanel {
private javax.swing.JPanel selectionPanel;
// End of variables declaration//GEN-END:variables
}
//TODO
//TODO test with linux
@@ -1533,9 +1533,9 @@ public class DataBrowser extends javax.swing.JFrame implements ConnectionTypeCha
}
if (connectedAliases.contains(node.alias)) {
((JLabel) render).setText("<html><nobr><b>" + UIUtil.toHTMLFragment(((JLabel) render).getText(), 0) + "&nbsp;&nbsp;&nbsp;</b></html>");
((JLabel) render).setText("<html><nobr><b>" + UIUtil.toHTMLFragment(((JLabel) render).getText(), 0) + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</b></html>");
} else {
((JLabel) render).setText("<html><nobr>" + UIUtil.toHTMLFragment(((JLabel) render).getText(), 0) + "&nbsp;&nbsp;&nbsp;</html>");
((JLabel) render).setText("<html><nobr>" + UIUtil.toHTMLFragment(((JLabel) render).getText(), 0) + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</html>");
}
} else {
icon = modelIcon;