/*
* Copyright 2007 - 2017 the original author or authors.
*
* 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.
*/
package net.sf.jailer.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import net.sf.jailer.ExecutionContext;
import net.sf.jailer.JailerVersion;
import net.sf.jailer.datamodel.DataModel;
import net.sf.jailer.datamodel.Table;
import net.sf.jailer.modelbuilder.ModelBuilder;
import net.sf.jailer.util.CsvFile;
import net.sf.jailer.util.CsvFile.Line;
import net.sf.jailer.util.CsvFile.LineFilter;
import net.sf.jailer.util.PrintUtil;
/**
* Data Model Editor.
*
* @author Ralf Wisser
*/
public class DataModelEditor extends javax.swing.JDialog {
public static final String DATA_MODEL_EDITOR_AUTHOR = "Data Model Editor";
/**
* List of tables.
*/
private List<CsvFile.Line> tables;
/**
* Maps table names to display names.
*/
private Map<String, String> displayNames;
/**
* List of associations.
*/
private List<CsvFile.Line> associations;
/**
* Table- and association definitions from model-finder result files.
*/
private List<CsvFile.Line> linesFromModelFinder = new ArrayList<CsvFile.Line>();
/**
* Set of tables with modified columns.
*/
private Set<String> modifiedColumnTables = new HashSet<String>();
/**
* Columns for each table.
*/
private Map<String, CsvFile.Line> columns = new TreeMap<String, Line>();
/**
* List of tables to be excluded from deletion.
*/
private List<String> excludeFromDeletion = new ArrayList<String>();
/**
* <code>true</code> iff model is modified.
*/
private boolean needsSave = false;
/**
* <code>true</code> iff model is saved.
*/
public boolean saved = false;
/**
* The execution context.
*/
private final ExecutionContext executionContext = CommandLineInstance.getExecutionContext();
/**
* Creates new form DataModelEditor.
*
* @param toEdit if not null, open table editor for this table immediately
* @param assocFilter
* @param tableFilter
*/
public DataModelEditor(java.awt.Frame parent, boolean merge, boolean initiallyDirty, final Table toEdit, LineFilter tableFilter, LineFilter assocFilter, String modelname, String modelnameSuggestion) throws Exception {
super(parent, true);
tables = new CsvFile(new File(DataModel.getTablesFile(executionContext)), tableFilter).getLines();
displayNames = new TreeMap<String, String>();
File dnFile = new File(DataModel.getDisplayNamesFile(executionContext));
if (dnFile.exists()) {
for (CsvFile.Line dnl: new CsvFile(dnFile).getLines()) {
displayNames.put(dnl.cells.get(0), dnl.cells.get(1));
}
}
associations = new CsvFile(new File(DataModel.getAssociationsFile(executionContext)), assocFilter).getLines();
boolean isDemoModel = tables.size() > 0;
for (CsvFile.Line dt: tables) {
String lastV = null;
for (String v: dt.cells) {
if (v != null && v.trim().length() > 0) {
lastV = v.trim();
}
}
if (lastV != null) {
if (!"Demo".equals(lastV)) {
isDemoModel = false;
break;
}
}
}
if (merge && isDemoModel) {
tables.clear();
associations.clear();
initiallyDirty = true;
} else {
PrintUtil.loadTableList(excludeFromDeletion, DataModel.getExcludeFromDeletionFile(executionContext));
}
int newTables = 0;
int newAssociations = 0;
File file = new File(DataModel.getColumnsFile(executionContext));
if (file.exists()) {
for (CsvFile.Line l: new CsvFile(file).getLines()) {
columns.put(l.cells.get(0), l);
}
}
File modelFinderTablesFile = new File(ModelBuilder.getModelBuilderTablesFilename(executionContext));
if (merge && modelFinderTablesFile.exists()) {
List<CsvFile.Line> tablesFromModelFinder = new CsvFile(modelFinderTablesFile).getLines();
for (Iterator<CsvFile.Line> i = tablesFromModelFinder.iterator(); i.hasNext(); ) {
CsvFile.Line t = i.next();
for (CsvFile.Line l: tables) {
boolean eq = true;
int n = 0;
while (n < l.cells.size() && n < t.cells.size()) {
if (n != 1 // ignore upsert flag
&& !l.cells.get(n).equals(t.cells.get(n))) {
eq = false;
break;
}
if (l.cells.get(n).length() == 0) {
break;
}
++n;
}
if (eq) {
i.remove();
break;
}
}
}
linesFromModelFinder.addAll(tablesFromModelFinder);
for (Iterator<CsvFile.Line> i = tables.iterator(); i.hasNext(); ) {
CsvFile.Line t = i.next();
for (CsvFile.Line l: linesFromModelFinder) {
if (l.cells.get(0).equals(t.cells.get(0))) {
i.remove();
break;
}
}
}
tables.addAll(tablesFromModelFinder);
newTables += tablesFromModelFinder.size();
}
sortLineList(tables, true);
File modelFinderAssociationsFile = new File(ModelBuilder.getModelBuilderAssociationsFilename(executionContext));
if (merge && modelFinderAssociationsFile.exists()) {
List<CsvFile.Line> associationsFromModelFinder = new CsvFile(modelFinderAssociationsFile).getLines();
associations.addAll(associationsFromModelFinder);
linesFromModelFinder.addAll(associationsFromModelFinder);
newAssociations += associationsFromModelFinder.size();
}
sortLineList(associations, false);
initComponents();
String modelpath = executionContext.getQualifiedDatamodelFolder();
try {
modelpath = new File(modelpath).getAbsolutePath();
} catch (Throwable t) {
// use default modelpath
}
locationLabel.setText(modelpath);
locationLabel.setToolTipText(modelpath);
if (modelnameSuggestion != null) {
if (merge && isDemoModel || DataModel.DEFAULT_NAME.equals(modelname) || "Demo".equals(modelname)) {
modelname = modelnameSuggestion;
}
}
nameTextField.setText(modelname);
nameTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent arg0) {
markDirty();
}
@Override
public void insertUpdate(DocumentEvent arg0) {
markDirty();
}
@Override
public void changedUpdate(DocumentEvent arg0) {
markDirty();
}
});
UIUtil.wireComponentWithButton(tablesList, editTable);
UIUtil.wireComponentWithButton(associationsList, editAssociation);
setSize(900, 700);
setLocation(100, 32);
File modelFinderColumnFile = new File(ModelBuilder.getModelBuilderColumnsFilename(executionContext));
if (merge && modelFinderColumnFile.exists()) {
for (CsvFile.Line l: new CsvFile(modelFinderColumnFile).getLines()) {
CsvFile.Line ol = columns.get(l.cells.get(0));
if (ol == null || !ol.cells.equals(l.cells)) {
modifiedColumnTables.add(l.cells.get(0));
markDirty();
}
columns.put(l.cells.get(0), l);
}
}
if (merge) {
info.setText("Found " + newTables + " new tables and " + newAssociations + " new associations");
if (!linesFromModelFinder.isEmpty()) {
markDirty();
}
}
info.setVisible(merge);
updateButtons();
final Color BG_COLOR = new Color(0.8f, 1.0f, 0.6f);
final Color BG_SELCOLOR = new Color(0.4f, 1.0f, 0.1f);
ListCellRenderer tablesListItemRenderer = new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
boolean fromModelFinder = linesFromModelFinder.contains(value);
CsvFile.Line line = (CsvFile.Line) value;
String tableName = line.cells.get(0);
String pk = "";
for (int i = 2; i < line.length; ++i) {
if (line.cells.get(i).length() == 0) {
break;
}
if (pk.length() > 0) {
pk += ", ";
}
pk += line.cells.get(i);
}
value = line.cells.get(0) + (pk.isEmpty()? "" : (" (" + pk + ")"));
Component render = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (pk.equals("")) {
render.setForeground(Color.RED);
}
if (fromModelFinder || modifiedColumnTables.contains(tableName)) {
render.setBackground(isSelected? BG_SELCOLOR : BG_COLOR);
}
return render;
}
private static final long serialVersionUID = -8591324056536900244L;
};
ListCellRenderer associationsListItemRenderer = new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
boolean fromModelFinder = linesFromModelFinder.contains(value);
CsvFile.Line line = (CsvFile.Line) value;
String type = "associates";
if ("B".equalsIgnoreCase(line.cells.get(2))) {
type = "depends on (has parent)";
}
if ("A".equalsIgnoreCase(line.cells.get(2))) {
type = "has dependent (has child)";
}
String name = "";
if (line.cells.get(5).length() > 0) {
name = "(" + line.cells.get(5) + ") ";
}
value = line.cells.get(0) + " " + type + " " + line.cells.get(1) + " " + name + line.cells.get(3) + " on " + line.cells.get(4);
Component render = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (fromModelFinder) {
render.setBackground(isSelected? BG_SELCOLOR: BG_COLOR);
}
return render;
}
private static final long serialVersionUID = -6057505075587930064L;
};
tablesList.setCellRenderer(tablesListItemRenderer);
associationsList.setCellRenderer(associationsListItemRenderer);
invalidate();
if (initiallyDirty) {
markDirty();
}
UIUtil.initPeer();
if (toEdit != null) {
addWindowListener(new WindowListener() {
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowOpened(WindowEvent e) {
for (Line l: tables) {
if (toEdit.getName().equals(l.cells.get(0))) {
if (new TableEditor(DataModelEditor.this, displayNames, tables, associations, excludeFromDeletion).edit(l, columns)) {
markDirty();
repaint();
}
break;
}
}
}
});
}
if (merge) {
ModelBuilder.cleanUp(executionContext);
}
}
/**
* Marks data model as modified.
*/
private void markDirty() {
if (!needsSave) {
needsSave = true;
setTitle("*" + getTitle());
}
}
/**
* Sorts lists of csv-lines.
*
* @param lines the list to sort
*/
private void sortLineList(List<CsvFile.Line> list, final boolean sortTables) {
Collections.sort(list, new Comparator<CsvFile.Line> () {
public int compare(CsvFile.Line o1, CsvFile.Line o2) {
int c1 = linesFromModelFinder.contains(o1)? 0 : 1;
int c2 = linesFromModelFinder.contains(o2)? 0 : 1;
if (c1 != c2) {
return c1 - c2;
}
if (sortTables) {
String pk1 = o1.cells.get(2);
String pk2 = o2.cells.get(2);
if (pk1.length() == 0 && pk2.length() > 0) return -1;
if (pk1.length() > 0 && pk2.length() == 0) return 1;
}
for (int i = 0; i < 3; ++i) {
int r = o1.cells.get(i).compareTo(o2.cells.get(i));
if (r != 0) {
return r;
}
}
return 0;
}
});
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
jPanel6 = new javax.swing.JPanel();
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
jPanel1 = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
tablesList = new javax.swing.JList();
jPanel4 = new javax.swing.JPanel();
newTable = new javax.swing.JButton();
editTable = new javax.swing.JButton();
deleteTables = new javax.swing.JButton();
jPanel3 = new javax.swing.JPanel();
jPanel5 = new javax.swing.JPanel();
newAssociation = new javax.swing.JButton();
editAssociation = new javax.swing.JButton();
deleteAssociations = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
associationsList = new javax.swing.JList();
info = new javax.swing.JLabel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
locationLabel = new javax.swing.JLabel();
nameTextField = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
setTitle("Data Model Editor");
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
getContentPane().setLayout(new java.awt.GridBagLayout());
okButton.setText("Ok");
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
jPanel6.add(okButton);
cancelButton.setText("Cancel");
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
jPanel6.add(cancelButton);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 20;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
getContentPane().add(jPanel6, gridBagConstraints);
jPanel1.setLayout(new java.awt.GridLayout(1, 0));
jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Tables"));
jPanel2.setLayout(new java.awt.GridBagLayout());
tablesList.setModel(createTablesListModel());
tablesList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
tablesListValueChanged(evt);
}
});
jScrollPane1.setViewportView(tablesList);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel2.add(jScrollPane1, gridBagConstraints);
jPanel4.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 2, 2));
newTable.setText("Add");
newTable.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newTableActionPerformed(evt);
}
});
jPanel4.add(newTable);
editTable.setText("Edit");
editTable.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editTableActionPerformed(evt);
}
});
jPanel4.add(editTable);
deleteTables.setText("Delete");
deleteTables.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteTablesActionPerformed(evt);
}
});
jPanel4.add(deleteTables);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
jPanel2.add(jPanel4, gridBagConstraints);
jPanel1.add(jPanel2);
jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Associations"));
jPanel3.setLayout(new java.awt.GridBagLayout());
jPanel5.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 2, 2));
newAssociation.setText("Add");
newAssociation.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newAssociationActionPerformed(evt);
}
});
jPanel5.add(newAssociation);
editAssociation.setText("Edit");
editAssociation.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editAssociationActionPerformed(evt);
}
});
jPanel5.add(editAssociation);
deleteAssociations.setText("Delete");
deleteAssociations.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteAssociationsActionPerformed(evt);
}
});
jPanel5.add(deleteAssociations);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
jPanel3.add(jPanel5, gridBagConstraints);
associationsList.setModel(createAssociationsListModel());
associationsList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
associationsListValueChanged(evt);
}
});
jScrollPane2.setViewportView(associationsList);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 2.0;
gridBagConstraints.weighty = 1.0;
jPanel3.add(jScrollPane2, gridBagConstraints);
jPanel1.add(jPanel3);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 10;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0);
getContentPane().add(jPanel1, gridBagConstraints);
info.setForeground(new java.awt.Color(1, 111, 1));
info.setText("jLabel1");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
getContentPane().add(info, gridBagConstraints);
jLabel1.setText(" Name ");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
getContentPane().add(jLabel1, gridBagConstraints);
jLabel2.setText(" Location ");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
getContentPane().add(jLabel2, gridBagConstraints);
locationLabel.setText(" Location ");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
getContentPane().add(locationLabel, gridBagConstraints);
nameTextField.setText("jTextField1");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 22);
getContentPane().add(nameTextField, gridBagConstraints);
pack();
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
save();
}//GEN-LAST:event_okButtonActionPerformed
private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
close();
}//GEN-LAST:event_formWindowClosing
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
close();
}//GEN-LAST:event_cancelButtonActionPerformed
private void newAssociationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newAssociationActionPerformed
List<String> cells = new ArrayList<String>();
for (int i = 0; i < 100; ++i) {
cells.add("");
}
CsvFile.Line line = new CsvFile.Line("?", cells);
if (new AssociationEditor(this, tables, associations).edit(line)) {
associations.add(0, line);
associationsList.setModel(createAssociationsListModel());
repaint();
markDirty();
}
}//GEN-LAST:event_newAssociationActionPerformed
private void editAssociationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editAssociationActionPerformed
CsvFile.Line line = null;
for (int i = 0; i < associations.size(); ++i) {
if (associationsList.getSelectionModel().isSelectedIndex(i)) {
line = associations.get(i);
break;
}
}
if (line != null) {
if (new AssociationEditor(this, tables, associations).edit(line)) {
markDirty();
repaint();
}
}
}//GEN-LAST:event_editAssociationActionPerformed
private void newTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTableActionPerformed
List<String> cells = new ArrayList<String>();
cells.add("");
cells.add("N");
cells.add("");
cells.add(DATA_MODEL_EDITOR_AUTHOR);
for (int i = 0; i < 100; ++i) {
cells.add("");
}
CsvFile.Line line = new CsvFile.Line("?", cells);
if (new TableEditor(this, displayNames, tables, associations, excludeFromDeletion).edit(line, columns)) {
tables.add(0, line);
tablesList.setModel(createTablesListModel());
markDirty();
repaint();
}
}//GEN-LAST:event_newTableActionPerformed
private void editTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editTableActionPerformed
CsvFile.Line line = null;
for (int i = 0; i < tables.size(); ++i) {
if (tablesList.getSelectionModel().isSelectedIndex(i)) {
line = tables.get(i);
break;
}
}
if (line != null) {
if (new TableEditor(this, displayNames, tables, associations, excludeFromDeletion).edit(line, columns)) {
markDirty();
repaint();
}
}
}//GEN-LAST:event_editTableActionPerformed
private void updateButtons() {
editTable.setEnabled(!tablesList.isSelectionEmpty());
deleteTables.setEnabled(!tablesList.isSelectionEmpty());
editAssociation.setEnabled(!associationsList.isSelectionEmpty());
deleteAssociations.setEnabled(!associationsList.isSelectionEmpty());
}
private void associationsListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_associationsListValueChanged
updateButtons();
}//GEN-LAST:event_associationsListValueChanged
private void tablesListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_tablesListValueChanged
updateButtons();
}//GEN-LAST:event_tablesListValueChanged
private void deleteTablesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTablesActionPerformed
Collection<CsvFile.Line> toDelete = new ArrayList<CsvFile.Line>();
Collection<String> namesOfTablesToDelete = new ArrayList<String>();
for (int i = 0; i < tables.size(); ++i) {
if (tablesList.getSelectionModel().isSelectedIndex(i)) {
Line table = tables.get(i);
if (table != null) {
toDelete.add(table);
namesOfTablesToDelete.add(table.cells.get(0));
}
}
}
Collection<CsvFile.Line> assToDelete = new HashSet<CsvFile.Line>();
for (CsvFile.Line t: toDelete) {
for (CsvFile.Line a: associations) {
if (a.cells.get(0).equalsIgnoreCase(t.cells.get(0)) || a.cells.get(1).equalsIgnoreCase(t.cells.get(0))) {
assToDelete.add(a);
}
}
}
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(this, "Delete " + toDelete.size() + " tables with\n" + assToDelete.size() + " related associations?", "Delete Table", JOptionPane.YES_NO_OPTION)) {
tables.removeAll(toDelete);
for (String k: namesOfTablesToDelete) {
displayNames.remove(k);
}
excludeFromDeletion.removeAll(namesOfTablesToDelete);
tablesList.setModel(createTablesListModel());
associations.removeAll(assToDelete);
associationsList.setModel(createAssociationsListModel());
for (Line l: toDelete) {
columns.remove(l.cells.get(0));
}
markDirty();
}
}//GEN-LAST:event_deleteTablesActionPerformed
private void deleteAssociationsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteAssociationsActionPerformed
Collection<CsvFile.Line> toDelete = new ArrayList<CsvFile.Line>();
for (int i = 0; i < associations.size(); ++i) {
if (associationsList.getSelectionModel().isSelectedIndex(i)) {
toDelete.add(associations.get(i));
}
}
associations.removeAll(toDelete);
associationsList.setModel(createAssociationsListModel());
markDirty();
}//GEN-LAST:event_deleteAssociationsActionPerformed
/**
* Creates model for tables-list component.
*
* @return model for tables-list component
*/
private ListModel createTablesListModel() {
DefaultListModel tablesListModel = new DefaultListModel();
for (CsvFile.Line line: tables) {
tablesListModel.addElement(line);
}
return tablesListModel;
}
/**
* Creates model for associations-list component.
*
* @return model for associations-list component
*/
private ListModel createAssociationsListModel() {
DefaultListModel associationsListModel = new DefaultListModel();
for (CsvFile.Line line: associations) {
associationsListModel.addElement(line);
}
return associationsListModel;
}
/**
* Closes editor.
*/
private void close() {
if (needsSave) {
if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(this, "Close without save?", "Close", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)) {
return;
}
}
setVisible(false);
}
/**
* Saves the model.
*/
private void save() {
try {
if (needsSave) {
save(tables, DataModel.getTablesFile(executionContext), "# Name; Upsert; Primary key; ; Author");
save(associations, DataModel.getAssociationsFile(executionContext), "# Table A; Table B; First-insert; Cardinality; Join-condition; Name; Author");
save(new ArrayList<Line>(columns.values()), DataModel.getColumnsFile(executionContext), "# Table; Columns");
saveTableList(excludeFromDeletion, DataModel.getExcludeFromDeletionFile(executionContext));
saveTableList(Arrays.asList(JailerVersion.VERSION), DataModel.getVersionFile(executionContext));
saveDisplayNames();
saveName();
saved = true;
}
} catch (Throwable t) {
UIUtil.showException(this, "Error", t);
}
setVisible(false);
}
/**
* Saves the display names.
*/
private void saveDisplayNames() throws FileNotFoundException {
PrintWriter out = new PrintWriter(DataModel.getDisplayNamesFile(executionContext));
out.println("# table; display name");
for (Map.Entry<String, String> e: displayNames.entrySet()) {
out.println(CsvFile.encodeCell(e.getKey()) + "; " + CsvFile.encodeCell(e.getValue()));
}
out.close();
}
/**
* Saves the model name.
*/
private void saveName() throws FileNotFoundException {
createNameFile(nameTextField.getText());
}
/**
* Saves the model name.
*/
public static void createNameFile(String name) throws FileNotFoundException {
PrintWriter out = new PrintWriter(DataModel.getModelNameFile(CommandLineInstance.getExecutionContext()));
out.println("# name; last modification");
out.println(CsvFile.encodeCell(name) + "; " + CsvFile.encodeCell(Long.toString(new Date().getTime())));
out.close();
}
/**
* Save a table list.
*
* @param tableList list to save
* @param fileName the file to save into
*/
private void saveTableList(List<String> tableList, String fileName) throws FileNotFoundException {
PrintWriter out = new PrintWriter(fileName);
for (String table: tableList) {
out.println(table);
}
out.close();
}
/**
* Saves a list of csv-lines.
*
* @param lines the lines
* @param fileName the file to save into
* @param title title line
*/
private void save(List<Line> lines, String fileName, String title) throws FileNotFoundException {
PrintWriter out = new PrintWriter(fileName);
out.println(title);
for (Line line: lines) {
out.println(line);
}
out.close();
}
/**
* Compares current model with the previous one.
*
* @return <code>true</code> if something has changed
*/
public boolean dataModelHasChanged() throws Exception {
String tmpFile = DataModel.getDatamodelFolder(executionContext) + File.separator + "tempcsv.tmp";
boolean result = false;
save(tables, tmpFile, "#");
result = !cvsFilesEquals(tmpFile, DataModel.getTablesFile(executionContext));
if (!result) {
save(associations, tmpFile, "#");
result = !cvsFilesEquals(tmpFile, DataModel.getAssociationsFile(executionContext));
}
if (!result) {
save(new ArrayList<Line>(columns.values()), tmpFile, "#");
result = !cvsFilesEquals(tmpFile, DataModel.getColumnsFile(executionContext));
}
if (!result) {
JOptionPane.showMessageDialog(this, "No changes found.", "Analyze Database", JOptionPane.INFORMATION_MESSAGE);
}
new File(tmpFile).delete();
return result;
}
/**
* Compares two csv files.
* @throws Exception
*/
private boolean cvsFilesEquals(String aFile, String bFile) throws Exception {
Set<String> a = new TreeSet<String>();
StringBuilder sb = new StringBuilder();
for (Line line: new CsvFile(new File(aFile)).getLines()) {
sb.setLength(0);
for (int i = 0; i < line.length; ++i) {
sb.append(line.cells.get(i)).append(';');
}
a.add(sb.toString());
}
Set<String> b = new TreeSet<String>();
for (Line line: new CsvFile(new File(bFile)).getLines()) {
sb.setLength(0);
for (int i = 0; i < line.length; ++i) {
sb.append(line.cells.get(i)).append(';');
}
b.add(sb.toString());
}
return a.equals(b);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList associationsList;
private javax.swing.JButton cancelButton;
private javax.swing.JButton deleteAssociations;
private javax.swing.JButton deleteTables;
private javax.swing.JButton editAssociation;
private javax.swing.JButton editTable;
private javax.swing.JLabel info;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JPanel jPanel4;
private javax.swing.JPanel jPanel5;
private javax.swing.JPanel jPanel6;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JLabel locationLabel;
private javax.swing.JTextField nameTextField;
private javax.swing.JButton newAssociation;
private javax.swing.JButton newTable;
private javax.swing.JButton okButton;
private javax.swing.JList tablesList;
// End of variables declaration//GEN-END:variables
private static final long serialVersionUID = -1267039412732180237L;
}