import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.math.*;
import javax.swing.undo.UndoManager;
import java.awt.datatransfer.*;
import javax.swing.event.AncestorListener;
import javax.swing.event.AncestorEvent;
import javax.swing.Timer;
import java.awt.datatransfer.StringSelection;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.nio.charset.Charset;
import java.awt.geom.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import static x30_pkg.x30_util.DynamicObject;
import java.nio.file.Path;
import java.text.*;
import java.util.TimeZone;
class main {
static boolean SimpleCRUD_searcher = true;
static class SimpleCRUD {
Concepts concepts;
Class cc;
JTable table;
JPanel buttons, panel;
Object renderer; // optional, func(A) -> Map
Object sorter; // optional, func(Cl) -> Cl
String hID = "ID";
Set unshownFields; // not shown in table or form
Set excludeFieldsFromEditing;
String modifiedField; // field to hold last-modified timestamp
TableSearcher tableSearcher;
Set multiLineFields; // string fields that should be shown as text areas
Set dontDuplicateFields;
boolean latestFirst = false;
int formFixer = 12; // stupid value to make submit button appear
boolean editOnDoubleClick = true;
boolean ensureIndexed = false;
boolean showValuesAsStruct = false; // BREAKING CHANGE - used to be true
SimpleCRUD(Class cc) { this(db_mainConcepts(), cc); }
SimpleCRUD(Concepts concepts, Class cc) {
this.cc = cc;
this.concepts = concepts;}
SimpleCRUD show(String frameTitle) {
make();
showFrame(frameTitle, panel);
return this;
}
SimpleCRUD show() {
return show(plural(shortClassName(cc)));
}
SimpleCRUD showMaximized() { show(); maximizeFrame(panel); return this; }
JPanel makePanel() { return make(); }
JPanel make() {
db();
framesBot();
return make_dontStartBots();
}
JPanel make_dontStartBots() {
printVars("SimpleCRUD.make_dontStartBots", "concepts", concepts, "cc", cc, "count" , countConcepts(cc));
if (ensureIndexed)
indexConceptClass(concepts, cc);
// next line not in swing part to allow passing arguments
// from outside like showConceptsTable_afterUpdate
AutoCloseable __1 = tempSetTL(showConceptsTable_concepts, concepts); try {
AutoCloseable __2 = tempSetTL(showConceptsTable_latestFirst, latestFirst); try {
AutoCloseable __3 = tempSetTL(showConceptsTable_sorter, sorter); try {
AutoCloseable __4 = tempSetTL(showConceptsTable_dropFields, asList(unshownFields)); try {
AutoCloseable __5 = tempSetTL(dataToTable_useStruct, showValuesAsStruct); try {
table = makeConceptsTable(cc, wrapRenderer(renderer));
{ swing(new Runnable() { public void run() { try {
buttons = jRightAlignedLine(
jbutton("Add...", new Runnable() { public void run() { try { newConcept() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "newConcept()"; }}),
tableDependButton(table, jbutton("Edit", new Runnable() { public void run() { try {
editConcept(selectedConcept())
;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "editConcept(selectedConcept())"; }})),
tableDependButton(table, jbutton("Delete", new Runnable() { public void run() { try {
final List l = selectedConcepts();
startThread("Delete concepts", new Runnable() { public void run() { try {
withDBLock(concepts, new Runnable() { public void run() { try { for (A c : l) c.delete() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "for (A c : l) c.delete()"; }});
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "withDBLock(concepts, new Runnable() { public void run() { try { for (A c : ..."; }});
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "final List l = selectedConcepts();\r\n thread \"Delete concepts\" {\r\n..."; }})),
tableDependButton(table, jbutton("Duplicate...", new Runnable() { public void run() { try {
duplicateConcept(selectedConcept())
;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "duplicateConcept(selectedConcept())"; }})));
if (SimpleCRUD_searcher) {
tableSearcher = tableWithSearcher2(table, "withMargin" , true);
panel = centerAndSouthWithMargin(tableSearcher.panel, withBottomMargin(buttons));
} else
panel = centerAndSouthWithMargin(table, withBottomMargin(buttons));
Object fEdit = new VF1() { public void get(Integer row) { try { editConcept(conceptForRow(row)) ; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "editConcept(conceptForRow(row))"; }};
tablePopupMenuItem(table, "Edit...", fEdit);
if (editOnDoubleClick)
onDoubleClick(table, fEdit);
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "buttons = jRightAlignedLine(\r\n jbutton(\"Add...\", r { newConcept() }),\r..."; }}); }
return panel;
} finally { _close(__5); }} finally { _close(__4); }} finally { _close(__3); }} finally { _close(__2); }} finally { _close(__1); }}
Object wrapRenderer(final Object renderer) {
return renderer == null ? null : new F1() { public Object get(A a) { try {
return putAll(litorderedmap(hID, str(a.id)), (Map) callF(renderer, a));
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "putAll(litorderedmap(hID, str(a.id)), (Map) callF(renderer, a))"; }};
}
void newConcept() {
duplicateConcept(null);
}
void duplicateConcept(A oldConcept) {
final A c = unlisted(cc);
ccopyFieldsExcept(oldConcept, c, dontDuplicateFields);
final Map map = makeComponents(c);
Runnable r = new Runnable() { public void run() { try {
concepts.register(c);
saveData(c, map);
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "concepts.register(c);\r\n saveData(c, map);"; }};
AutoCloseable __6 = tempSetMCOpt("formLayouter1_fixer2" , formFixer); try {
showFormTitled2("New " + shortClassName(cc), arrayPlus(mapToObjectArray(map), r));
} finally { _close(__6); }}
void editConcept(final A c) {
if (c == null) return;
final Map map = makeComponents(c);
Runnable r = new Runnable() { public void run() { try { saveData(c, map) ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "saveData(c, map)"; }};
AutoCloseable __7 = tempSetMCOpt("formLayouter1_fixer2" , formFixer); try {
showFormTitled2("Edit " + shortClassName(cc) + " #" + c.id, arrayPlus(mapToObjectArray(map), r));
} finally { _close(__7); }}
A selectedConcept() { return selected(); }
A selected() {
return conceptForRow(selectedRow(table));
}
A conceptForRow(int row) {
return (A) concepts.getConcept(toLong(getTableCell(table, row, 0)));
}
int indexOfConcept(final A c) {
if (c == null) return -1;
return swing(new F0() { public Integer get() { try {
int n = tableRowCount(table);
for (int row = 0; row < n; row++)
if (toLong(getTableCell(table, row, 0)) == c.id)
return row;
return -1;
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "int n = tableRowCount(table);\r\n for row to n:\r\n if (toLong(getTab..."; }});
}
List selectedConcepts() {
return swing(() -> {
int[] rows = table == null ? null : table.getSelectedRows();
List l = new ArrayList();
for (int row : unnullForIteration(rows))
l.add(conceptForRow(row));
return l;
});
}
Map makeComponents(A c) {
Map map = litorderedmap();
makeComponents(c, map);
return map;
}
JComponent fieldComponent(A c, String field) {
Class type = getFieldType(cc, field);
Object value = getOpt(c, field);
//print("Field type: " + field + " => " + type);
if (type == boolean.class)
return jCenteredCheckBox(isTrue(value));
else if (contains(multiLineFields, field) || containsNewLines(optCast(String.class, value)))
return typeWriterTextArea((String) value);
else if (isSubtype(type, Concept.class))
return jcomboboxFromConcepts_str(concepts, type, (Concept) value);
else try {
return autoComboBox(valueToString(value), new TreeSet(map(__29 -> valueToString(__29), collect(list(concepts, cc), field))));
} catch (Throwable e) {
printException(e);
return jTextField(valueToString(value));
}
}
void saveComponent(A c, String field, JComponent comp) {
comp = unwrap(comp);
Class type = fieldType(c, field);
if (comp instanceof JTextComponent)
cset(c, field, convertToField(trimIf(!(comp instanceof JTextArea), getText((JTextComponent) comp)), cc, field));
else if (comp instanceof JComboBox) {
String text = getTextTrim((JComboBox) comp);
if (isSubtype(type, Concept.class))
cset(c, field, getConcept(concepts, parseFirstLong(text)));
else
cset(c, field, convertToField(text, cc, field));
} else if (comp instanceof JCheckBox)
cset(c, field, isChecked((JCheckBox) comp));
}
List fields() {
if (excludeFieldsFromEditing != null && modifiedField != null) excludeFieldsFromEditing.add(modifiedField);
return listWithoutSet(filter(conceptFieldsInOrder(cc) , new F1() { public Boolean get(String field) { try { return fieldType(cc, field) != Concept.Ref.class; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "fieldType(cc, field) != Concept.Ref.class"; }}),
joinSets(excludeFieldsFromEditing, unshownFields));
}
void excludeFieldsFromEditing(String... fields) {
excludeFieldsFromEditing = setPlus(excludeFieldsFromEditing, fields);
}
// override the following two methods to customize edit window
void makeComponents(A c, Map map) {
for (String field : fields())
map.put(field, fieldComponent(c, field));
}
void saveData(A c, Map components) {
for (String field : keys(components))
saveComponent(c, field, components.get(field));
if (modifiedField != null) cset(c, modifiedField, now());
}
JTable table() { return table; }
transient IF1