Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

230
LINES

< > BotCompany Repo | #1006540 // SimpleCRUD - create/read/update/delete for a concept class with simple fields [Swing]

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (25943L/171K).

1  
sbool SimpleCRUD_searcher = true;
2  
3  
sclass SimpleCRUD<A extends Concept> {
4  
  Concepts concepts;
5  
  Class<A> cc;
6  
  JTable table;
7  
  JPanel buttons, panel;
8  
  O renderer; // optional, func(A) -> Map
9  
  O sorter; // optional, func(Cl<Concept>) -> Cl<Concept>
10  
  S hID = "ID";
11  
  Set<S> unshownFields; // not shown in table or form
12  
  Set<S> excludeFieldsFromEditing;
13  
  S modifiedField; // field to hold last-modified timestamp
14  
  TableSearcher tableSearcher;
15  
  Set<S> multiLineFields; // string fields that should be shown as text areas
16  
  Set<S> dontDuplicateFields;
17  
  bool latestFirst;
18  
  int formFixer = 12; // stupid value to make submit button appear
19  
  bool editOnDoubleClick = true;
20  
  bool ensureIndexed;
21  
  bool showValuesAsStruct; // BREAKING CHANGE - used to be true
22  
23  
  *(Class<A> cc) { this(db_mainConcepts(), cc); }
24  
  *(Concepts *concepts, Class<A> *cc) {}
25  
  
26  
  SimpleCRUD<A> show(S frameTitle) {
27  
    make();
28  
    showFrame(frameTitle, panel);
29  
    this;
30  
  }
31  
  
32  
  SimpleCRUD<A> show() {
33  
    ret show(plural(shortClassName(cc)));
34  
  }
35  
  
36  
  SimpleCRUD<A> showMaximized() { show(); maximizeFrame(panel); ret this; }
37  
  
38  
  JPanel makePanel() { ret make(); }
39  
  JPanel make() {
40  
    db();
41  
    framesBot();
42  
    ret make_dontStartBots();
43  
  }
44  
  
45  
  JPanel make_dontStartBots() {
46  
    printVars("SimpleCRUD.make_dontStartBots", +concepts, +cc, count := countConcepts(cc));
47  
    if (ensureIndexed)
48  
      indexConceptClass(concepts, cc);
49  
50  
    // next line not in swing part to allow passing arguments
51  
    // from outside like showConceptsTable_afterUpdate
52  
    temp tempSetTL(showConceptsTable_concepts, concepts);
53  
    temp tempSetTL(showConceptsTable_latestFirst, latestFirst);
54  
    temp tempSetTL(showConceptsTable_sorter, sorter);
55  
    temp tempSetTL(showConceptsTable_dropFields, asList(unshownFields));
56  
    temp tempSetTL(dataToTable_useStruct, showValuesAsStruct);
57  
    table = makeConceptsTable(cc, wrapRenderer(renderer));
58  
    swing {
59  
      buttons = jRightAlignedLine(
60  
        jbutton("Add...", r { newConcept() }),
61  
        tableDependButton(table, jbutton("Edit", r {
62  
          editConcept(selectedConcept())
63  
        })),
64  
        tableDependButton(table, jbutton("Delete", r {
65  
          final L<A> l = selectedConcepts();
66  
          thread "Delete concepts" {
67  
            withDBLock(concepts, r { for (A c : l) c.delete() });
68  
          }
69  
        })),
70  
        tableDependButton(table, jbutton("Duplicate...", r {
71  
          duplicateConcept(selectedConcept())
72  
        })));
73  
        
74  
      if (SimpleCRUD_searcher) {
75  
        tableSearcher = tableWithSearcher2(table, withMargin := true);
76  
        panel = centerAndSouthWithMargin(tableSearcher.panel, withBottomMargin(buttons));
77  
      } else
78  
        panel = centerAndSouthWithMargin(table, withBottomMargin(buttons));
79  
      
80  
      O fEdit = voidfunc(int row) { editConcept(conceptForRow(row)) };
81  
      tablePopupMenuItem(table, "Edit...", fEdit);
82  
      if (editOnDoubleClick)
83  
        onDoubleClick(table, fEdit);
84  
    }
85  
    ret panel;
86  
  }
87  
  
88  
  O wrapRenderer(fO renderer) {
89  
    ret renderer == null ? null : func(A a) {
90  
      putAll(litorderedmap(hID, str(a.id)), (Map) callF(renderer, a))
91  
    };
92  
  }
93  
  
94  
  void newConcept {
95  
    duplicateConcept(null);
96  
  }
97  
    
98  
  void duplicateConcept(A oldConcept) {
99  
    final A c = unlisted(cc);
100  
    ccopyFieldsExcept(oldConcept, c, dontDuplicateFields);
101  
    final Map<S, JComponent> map = makeComponents(c);
102  
    Runnable r = r {
103  
      concepts.register(c);
104  
      saveData(c, map);
105  
    };
106  
    temp tempSetMCOpt(formLayouter1_fixer2 := formFixer);
107  
    showFormTitled2("New " + shortClassName(cc), arrayPlus(mapToObjectArray(map), r));
108  
  }
109  
110  
  void editConcept(final A c) {
111  
    if (c == null) ret;
112  
    final Map<S, JComponent> map = makeComponents(c);
113  
    Runnable r = r { saveData(c, map) };
114  
    temp tempSetMCOpt(formLayouter1_fixer2 := formFixer);
115  
    showFormTitled2("Edit " + shortClassName(cc) + " #" + c.id, arrayPlus(mapToObjectArray(map), r));
116  
  }
117  
  
118  
  A selected aka selectedConcept() {
119  
    ret conceptForRow(selectedRow(table));
120  
  }
121  
  
122  
  A conceptForRow(int row) {
123  
    ret (A) concepts.getConcept(toLong(getTableCell(table, row, 0)));
124  
  }
125  
  
126  
  int indexOfConcept(final A c) {
127  
    if (c == null) ret -1;
128  
    ret swing(func -> int {
129  
      int n = tableRowCount(table);
130  
      for row to n:
131  
        if (toLong(getTableCell(table, row, 0)) == c.id)
132  
          ret row;
133  
      ret -1;
134  
    });
135  
  }
136  
  
137  
  L<A> selectedConcepts() {
138  
    ret swing(() -> {
139  
      int[] rows = table?.getSelectedRows();
140  
      new L<A> l;
141  
      fOr (int row : rows)
142  
        l.add(conceptForRow(row));
143  
      ret l;
144  
    });
145  
  }
146  
  
147  
  Map<S, JComponent> makeComponents(A c) {
148  
    Map<S, JComponent> map = litorderedmap();
149  
    makeComponents(c, map);
150  
    ret map;
151  
  }
152  
  
153  
  JComponent fieldComponent(A c, S field) {
154  
    Class type = getFieldType(cc, field);
155  
    O value = getOpt(c, field);
156  
    //print("Field type: " + field + " => " + type);
157  
    if (type == bool.class)
158  
      ret jCenteredCheckBox(isTrue(value));
159  
    else if (contains(multiLineFields, field) || containsNewLines(optCast S(value)))
160  
      ret typeWriterTextArea((S) value);
161  
    else if (isSubtype(type, Concept))
162  
      ret jcomboboxFromConcepts_str(concepts, type, (Concept) value);
163  
    ifclass SecretValue
164  
    else if (type == SecretValue.class)
165  
      ret jpassword(strOrEmpty(getVar(value/SecretValue)));
166  
    endif
167  
    else try {
168  
      ret autoComboBox(valueToString(value), new TreeSet<S>(map valueToString(collect(list(concepts, cc), field))));
169  
    } catch e {
170  
      printException(e);
171  
      ret jTextField(valueToString(value));
172  
    }
173  
  }
174  
  
175  
  void saveComponent(A c, S field, JComponent comp) {
176  
    comp = unwrap(comp);
177  
    Class type = fieldType(c, field);
178  
    ifclass SecretValue
179  
      if (type == SecretValue.class) {
180  
        S text = getTextTrim((JPasswordField) comp);
181  
        cset(c, field, empty(text) ? null : SecretValue(text));
182  
      } else
183  
    endif
184  
    if (comp instanceof JTextComponent)
185  
      cset(c, field, convertToField(trimIf(!comp instanceof JTextArea, getText((JTextComponent) comp)), cc, field));
186  
    else if (comp cast JComboBox) {
187  
      S text = getTextTrim(comp);
188  
      if (isSubtype(type, Concept))
189  
        cset(c, field, getConcept(concepts, parseFirstLong(text)));
190  
      else
191  
        cset(c, field, convertToField(text, cc, field));
192  
    } else if (comp instanceof JCheckBox)
193  
      cset(c, field, isChecked((JCheckBox) comp));
194  
    ifclass ImageChooser
195  
      else if (comp instanceof ImageChooser)
196  
        cUpdatePNGFile(c, field, comp/ImageChooser.getImage(), false);
197  
    endif
198  
  }
199  
  
200  
  L<S> fields() {
201  
    if (excludeFieldsFromEditing != null && modifiedField != null) excludeFieldsFromEditing.add(modifiedField);
202  
    ret listWithoutSet([S field : conceptFieldsInOrder(cc) | fieldType(cc, field) != Concept.Ref.class],
203  
      joinSets(excludeFieldsFromEditing, unshownFields));
204  
  }
205  
  
206  
  void excludeFieldsFromEditing(S... fields) {
207  
    excludeFieldsFromEditing = setPlus(excludeFieldsFromEditing, fields);
208  
  }
209  
  
210  
  // override the following two methods to customize edit window
211  
  
212  
  void makeComponents(A c, Map<S, JComponent> map) {
213  
    for (S field : fields())
214  
      map.put(field, fieldComponent(c, field));
215  
  }
216  
  
217  
  void saveData(A c, Map<S, JComponent> components) {
218  
    for (S field : keys(components))
219  
      saveComponent(c, field, components.get(field));
220  
    if (modifiedField != null) cset(c, modifiedField, now());
221  
  }
222  
  
223  
  JTable table() { ret table; }
224  
  
225  
  swappable S valueToString(O o) {
226  
    ret showValuesAsStruct
227  
      ? structureOrText_crud(o)
228  
      : strOrNull(o);
229  
  }
230  
} // end of SimpleCRUD

Author comment

Ref<PNGFile> fields can be saved, but are not shown automatically

download  show line numbers  debug dex  old transpilations   

Travelled to 16 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1006540
Snippet name: SimpleCRUD - create/read/update/delete for a concept class with simple fields [Swing]
Eternal ID of this version: #1006540/99
Text MD5: 8b2fd8c89a872f145d98fef41bfaea1b
Transpilation MD5: a5d4304b3c919484906283274b0b3454
Author: stefan
Category: javax / concepts / gui
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-09-12 04:28:18
Source code size: 7766 bytes / 230 lines
Pitched / IR pitched: No / No
Views / Downloads: 995 / 2188
Version history: 98 change(s)
Referenced in: [show references]