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

298
LINES

< > BotCompany Repo | #1030725 // JConceptsTable - new version of showConceptsTable

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

Libraryless. Click here for Pure Java version (30096L/193K).

sclass JConceptsTable<A extends Concept> is Swingable {
  Class<? extends A> conceptClass;
  Concepts concepts;
  JTable table;
  
  // options
  MapSO filters; // fields to filter by/add to new objects
  S hID = "ID"; // Column header for concept ID
  settable LS dropFields;
  settable bool noSubclasses;
  IF1<L> postProcess;
  Runnable afterUpdate;
  bool latestFirst;
  IF1<Cl<A>> sorter = lambda1 defaultSort;
  int idWidth = 50;
  settable int updateInterval = 100;
  int firstUpdateInterval = 100;
  bool humanizeFieldNames = true;
  Float tableFontSize;
  Int tableRowHeight;
  settable bool addCountToEnclosingTab;
  settable bool useNewChangeHandler;
  settable IVF1<A> defaultAction;
  bool pauseUpdates;
  int count;
  
  event selectionChanged;
  event singleSelectionChanged;

  // internal
  AWTOnConceptChanges changeHandler;
  AWTOnConceptChangesByClass newChangeHandler;
  bool updatingList;
  settable A selectAfterUpdate;
  A lastSelected;
  
  *() {}
  *(Class<? extends A> *conceptClass) {}
  *(Concepts *concepts, Class<? extends A> *conceptClass) {}
  
  swappable MapSO itemToMap(A a) {
    MapSO map = specialFieldsForItem(a);
    try {
      putAll(map, mapValues renderValue(itemToMap_inner2(a)));
    } catch print e {
      map.put("Error", str(e));
    }
    ret map;
  }
  
  swappable O renderValue(O o) {
    ret renderForTable_noStruct(o);
  }
  
  swappable MapSO itemToMap_inner2(A a) {
    ret allConceptFieldsAsMapExcept(a, dropFields);
  }
  
  // shown on the left (usually)
  swappable MapSO specialFieldsForItem(A a) {
    MapSO map = litorderedmap(hID, str(a.id));
    mapPut(map, "Java Class", javaClassDescForItem(a));
    ret map;
  }
  
  S javaClassDescForItem(A a) {
    S className = dynShortClassName(a);
    if (neq(className, shortClassName(conceptClass))) {
      S text = className;
      S realClass = shortClassName(a);
      if (neq(className, realClass))
        text += " as " + realClass;
      ret text;
    }
    null;
  }
  
  S defaultTitle() {
    ret plural(shortClassName(conceptClass));
  }
  
  void showAsFrame(S title default defaultTitle()) {
    makeTable();
    showFrame(title, table);
  }
  
  void makeTable {
    if (table != null) ret;
    if (concepts == null) concepts = db_mainConcepts();

    table = sexyTable();
    if (tableFontSize != null) {
      setTableFontSizes(tableFontSize, table);
      if (tableRowHeight == null)
        tableRowHeight = iround(tableFontSize*1.5);
    }
    if (tableRowHeight != null) setRowHeight(table, tableRowHeight);
    
    if (useNewChangeHandler) {
      newChangeHandler = new AWTOnConceptChangesByClass(concepts, conceptClass, table, l0 _update)
       .delay(updateInterval)
       .firstDelay(firstUpdateInterval);
      newChangeHandler.install();
    } else {
      changeHandler = new AWTOnConceptChanges(concepts, table, l0 _update)
        .delay(updateInterval)
        .firstDelay(firstUpdateInterval);
      changeHandler.install();
    }
    
    onTableSelectionChanged(table, -> {
      if (updatingList) ret;
      selectionChanged();
    });
    
    onSelectionChanged(-> {
      var a = selected();
      if (a != lastSelected) {
        lastSelected = a;
        singleSelectionChanged();
      }
    });
    
    onDoubleClickOrEnter(table, -> {
      A a = selected();
      if (a != null && defaultAction != null)
        pcallF(defaultAction, a);
    });
  }
  
  // e.g. to update enclosing tab when hidden
  void update {
    swing { _update(); }
  }
  
  // run in Swing thread
  void _update {
    if (table == null || pauseUpdates) ret;
    set updatingList;
    bool allRestored;
    A selectAfterUpdate = selectAfterUpdate();
    
    try {
      new L<Map> data;
      
      Set<Long> selection;
      if (selectAfterUpdate != null) {
        selection = litset(selectAfterUpdate._conceptID());
        selectAfterUpdate(null);
      } else
        selection = toSet(selectedConceptIDs());
        
      Cl<? extends A> l = conceptsWhere(concepts, conceptClass, mapToParams(filters));
      if (noSubclasses) l = filter(l, x -> x.getClass() == conceptClass);
      l = postProcess(sorter, l);
      for (A c : l)
        addIfNotNull(data, itemToMap(c));
      if (latestFirst) reverseInPlace(data);
      data = (L) postProcess(postProcess, data);
      count = l(data);
      dataToTable_uneditable(data, table);
      if (humanizeFieldNames)
        humanizeTableColumns();
      tableColumnMaxWidth(table, 0, idWidth);
    
      allRestored = restoreSelection(selection);

      if (addCountToEnclosingTab)
        updateEnclosingTabTitle();
    } finally {
      updatingList = false;
    }
    
    pcallF(afterUpdate);
    
    if (!allRestored || selectAfterUpdate != null)
      selectionChanged();
  }
  
  void updateEnclosingTabTitle {
    updateEnclosingTabTitleWithCount(table, count);
  }
  
  void humanizeTableColumns {
    int n = tableColumnCount(table);
    for i to n:
      setColumnName(table, i, humanizeFormLabel(getColumnName(table, i)));
  };

  visual table();

  JTable table() {
    makeTable();
    ret table;
  }
  
  A selectedConcept() {
    ret (A) concepts.getConcept(toLong(selectedTableCell(table, 0)));
  }
  
  A selected() { ret selectedConcept(); }
  
  long getItemID(int row) {
    ret toLong(getTableCell(table, row, 0));
  }
  
  L<A> getList() swing {
    ret countIteratorAsList(size(), row -> getItem(row));
  }
  
  A getItem(int row) {
    ret (A) concepts.getConcept(getItemID(row));
  }
  
  int size() { ret tableRowCount(table); }
  
  int indexOfConcept(final A c) {
    if (c == null) ret -1;
    ret swing(func -> int {
      int n = size();
      for row to n:
        if (toLong(getTableCell(table, row, 0)) == c.id)
          ret row;
      ret -1;
    });
  }
  
  L<A> selectedConcepts() {
    ret swing(-> {
      int[] rows = table.getSelectedRows();
      new L<A> l;
      for (int row : rows)
        l.add(getItem(row));
      ret l;
    });
  }
  
  L<Long> selectedConceptIDs() {
    ret swing(-> {
      int[] rows = table.getSelectedRows();
      L<Long> l = emptyList(l(rows));
      for (int row : rows)
        l.add(getItemID(row));
      ret l;
    });
  }
  
  // returns true if all selected items still exist
  bool restoreSelection(Set<Long> selection) {
    ret swing(-> {
      int n = size();
      new IntBuffer toSelect;
      for row to n:
        if (selection.contains(getItemID(row)))
          toSelect.add(row);
      selectTableRows(table, toSelect.toIntArray());
      ret toSelect.size() == selection.size();
    });
  }
  
  void setSelected(A a) {
    selectRow(table(), indexOfConcept(a));
  }
  
  Cl<A> defaultSort(Cl<A> l) {
    ret sortByConceptID(l);
  }
  
  selfType addFilter(S field, O value) {
    filters = orderedMapPutOrCreate(filters, field, value);
    this;
  }
  
  void onSelectionChangedAndWhenShowing(Runnable r) {
    bindToComponent(table(), r);
    onSelectionChanged(r);
  }
  
  void onSelectionChangedAndNow(Runnable r) {
    if (r == null) ret;
    onSelectionChanged(r);
    r.run();
  }
  
  selfType updateInterval(double seconds) {
    ret updateInterval(toMS_int(seconds));
  }
  
  selfType pauseUpdates(bool b) {
    swing {
      if (pauseUpdates != b) {
        if (!(pauseUpdates = b))
          _update();
      }
    }
    this;
  }
}

Author comment

Began life as a copy of #1006009

download  show line numbers  debug dex  old transpilations   

Travelled to 5 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1030725
Snippet name: JConceptsTable - new version of showConceptsTable
Eternal ID of this version: #1030725/76
Text MD5: 0a61293494dec29dee23d130b6d6b4c8
Transpilation MD5: e4b404ad5e5c1dd7f30581e04988d005
Author: stefan
Category: javax / gui / concepts
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2023-01-17 18:40:16
Source code size: 7632 bytes / 298 lines
Pitched / IR pitched: No / No
Views / Downloads: 394 / 979
Version history: 75 change(s)
Referenced in: #1033925 - JConceptsTable - new version of showConceptsTable [backup before filters]
#1034021 - JObjectTable - like JConceptsTable but for any kind of object
#1034167 - Standard Classes + Interfaces (LIVE, continuation of #1003674)
#1034339 - JConceptsTable (backup before new selection change listener mechanism)