InspectorTable.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package ui.view.main;
  2. import java.awt.BorderLayout;
  3. import java.awt.Color;
  4. import java.awt.Container;
  5. import java.awt.Dimension;
  6. import java.math.RoundingMode;
  7. import java.text.NumberFormat;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.List;
  11. import java.util.Locale;
  12. import java.util.Optional;
  13. import java.util.stream.Collectors;
  14. import javax.swing.BorderFactory;
  15. import javax.swing.Box;
  16. import javax.swing.BoxLayout;
  17. import javax.swing.ImageIcon;
  18. import javax.swing.JButton;
  19. import javax.swing.JCheckBox;
  20. import javax.swing.JComboBox;
  21. import javax.swing.JFormattedTextField;
  22. import javax.swing.JLabel;
  23. import javax.swing.JPanel;
  24. import javax.swing.JTextField;
  25. import javax.swing.UIManager;
  26. import javax.swing.border.Border;
  27. import javax.swing.text.NumberFormatter;
  28. import classes.AbstractCanvasObject;
  29. import classes.HolonElement;
  30. import classes.HolonElement.Priority;
  31. import classes.HolonObject;
  32. import net.miginfocom.swing.MigLayout;
  33. import ui.controller.Control;
  34. import ui.view.component.TrippleCheckBox;
  35. import ui.view.component.TrippleCheckBox.State;
  36. import utility.ImageImport;
  37. import utility.events.SimpleDocumentListener;
  38. public class InspectorTable extends JPanel {
  39. private List<ElementRow> elementRows = new ArrayList<ElementRow>();
  40. private Control control;
  41. private final int columnHeight = 20;
  42. //UI
  43. private final TrippleCheckBox selectAllCheckBox = new TrippleCheckBox();
  44. private final JButton addButton = new JButton();
  45. private final JButton duplicateButton = new JButton();
  46. private final JButton deleteButton = new JButton();
  47. private final JPanel buttonPanel = new JPanel();
  48. private final NumberFormatter doubleFormatter = generateNumberFormatter();
  49. //Colors
  50. private final Color selectedColor = new Color(126, 186, 255);
  51. private final Color borderColor = new Color(171, 173, 179);
  52. public InspectorTable(Control control) {
  53. control.OnSelectionChanged.addListener(() -> update_ui());
  54. this.control = control;
  55. init();
  56. generateHeader();
  57. }
  58. private void init() {
  59. MigLayout layout = new MigLayout("insets 0,gap 0,wrap 7", // Layout Constraints
  60. "[][fill, grow][][fill, grow][fill, grow][][]", // Column constraints
  61. "[25!][20:20:20]"); // Row constraints
  62. this.setLayout(layout);
  63. initSelectAllCheckBox();
  64. initButtonPanel();
  65. }
  66. private void generateHeader() {
  67. this.add(selectAllCheckBox);
  68. this.add(generateHeaderColumnTitle("Object"));
  69. this.add(generateHeaderColumnTitle("Id "));
  70. this.add(generateHeaderColumnTitle("Device"));
  71. this.add(generateHeaderColumnTitle("Energy"));
  72. this.add(generateHeaderColumnTitle("Priority"));
  73. this.add(generateHeaderColumnTitle("Activ"));
  74. }
  75. private void initSelectAllCheckBox() {
  76. selectAllCheckBox.setBorder(generateButtonHeaderBorder());
  77. // Pixel Perfect alignment
  78. selectAllCheckBox.setBorder(BorderFactory.createEmptyBorder(2, 3, 0, 0));
  79. selectAllCheckBox.addActionListener(clicked -> {
  80. switch (selectAllCheckBox.getSelectionState()) {
  81. case mid_state_selection:
  82. case selected: {
  83. for (ElementRow row : elementRows) {
  84. row.setSelected(false);
  85. }
  86. duplicateButton.setEnabled(false);
  87. deleteButton.setEnabled(false);
  88. }
  89. break;
  90. case unselected:
  91. for (ElementRow row : elementRows) {
  92. row.setSelected(true);
  93. }
  94. duplicateButton.setEnabled(true);
  95. deleteButton.setEnabled(true);
  96. default:
  97. break;
  98. }
  99. });
  100. }
  101. public void update_ui() {
  102. System.out.println("update_ui");
  103. List<HolonElement> elements = extractElements(control.getModel().getSelectedObjects());
  104. // TODO Pooling
  105. this.removeAll();
  106. elementRows.clear();
  107. generateHeader();
  108. for (HolonElement element : elements) {
  109. elementRows.add(new ElementRow(element));
  110. }
  111. this.add(buttonPanel, "span");
  112. duplicateButton.setEnabled(false);
  113. deleteButton.setEnabled(false);
  114. selectAllCheckBox.setSelectionState(State.unselected);
  115. revalidate();
  116. repaint();
  117. }
  118. private JLabel generateHeaderColumnTitle(String string) {
  119. JLabel columnTitleLabel = new JLabel(string);
  120. columnTitleLabel.setToolTipText(string);
  121. columnTitleLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  122. return columnTitleLabel;
  123. }
  124. private void initButtonPanel() {
  125. buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
  126. buttonPanel.add(Box.createRigidArea(new Dimension(2, 0)));
  127. addButton.setIcon(new ImageIcon(ImageImport.loadImage("Images/plus.png", 16, 16)));
  128. addButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  129. addButton.addActionListener(clicked -> {
  130. System.out.println("AddButton");
  131. Optional<HolonObject> last = control.getModel().getSelectedObjects().stream()
  132. .filter(obj -> obj instanceof HolonObject).reduce((prev, next) -> next)
  133. .map(obj -> (HolonObject) obj);
  134. last.ifPresent(obj -> {
  135. obj.addElement(new HolonElement(obj, "Element", 0.0f));
  136. });
  137. control.calculateStateAndVisualForCurrentTimeStep();
  138. update_ui();
  139. });
  140. buttonPanel.add(addButton);
  141. duplicateButton.setIcon(new ImageIcon(ImageImport.loadImage("Images/duplicate.png", 16, 16)));
  142. duplicateButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  143. duplicateButton.addActionListener(clicked -> {
  144. for (ElementRow row : elementRows) {
  145. if(row.isSelected()) {
  146. row.element.parentObject.addElement(new HolonElement(row.element));
  147. }
  148. }
  149. control.calculateStateAndVisualForCurrentTimeStep();
  150. update_ui();
  151. });
  152. buttonPanel.add(duplicateButton);
  153. deleteButton.setIcon(new ImageIcon(ImageImport.loadImage("Images/minus.png", 16, 16)));
  154. deleteButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
  155. deleteButton.addActionListener(clicked -> {
  156. for (ElementRow row : elementRows) {
  157. if(row.isSelected()) {
  158. row.element.parentObject.removeElement(row.element);
  159. }
  160. }
  161. control.calculateStateAndVisualForCurrentTimeStep();
  162. update_ui();
  163. });
  164. buttonPanel.add(deleteButton);
  165. }
  166. // Extract elements from a list of AbstractCanvasObjects
  167. private List<HolonElement> extractElements(Collection<AbstractCanvasObject> toInspect) {
  168. return toInspect.stream().filter(obj -> obj instanceof HolonObject).flatMap(obj -> {
  169. HolonObject ho = (HolonObject) obj;
  170. return ho.getElements().stream();
  171. }).collect(Collectors.toList());
  172. }
  173. private NumberFormatter generateNumberFormatter() {
  174. NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
  175. doubleFormat.setMinimumFractionDigits(1);
  176. doubleFormat.setMaximumFractionDigits(10);
  177. doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
  178. doubleFormat.setGroupingUsed(false);
  179. NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
  180. doubleFormatter.setCommitsOnValidEdit(true);
  181. doubleFormatter.setValueClass(Double.class);
  182. return doubleFormatter;
  183. }
  184. private Border generateButtonHeaderBorder() {
  185. return BorderFactory.createEmptyBorder(2, 0, 0, 0);
  186. }
  187. private void setSelectAllCheckBox() {
  188. long count = elementRows.stream().filter(ele -> ele.isSelected()).count();
  189. if (count == elementRows.size()) {
  190. selectAllCheckBox.setSelectionState(State.selected);
  191. } else if (count == 0) {
  192. selectAllCheckBox.setSelectionState(State.unselected);
  193. } else {
  194. selectAllCheckBox.setSelectionState(State.mid_state_selection);
  195. }
  196. duplicateButton.setEnabled(count != 0);
  197. deleteButton.setEnabled(count != 0);
  198. selectAllCheckBox.repaint();
  199. }
  200. private class ElementRow {
  201. HolonElement element;
  202. private JCheckBox selectionBox;
  203. Container[] cellsInRow = new Container[7];
  204. ElementRow(HolonElement element) {
  205. this.element = element;
  206. this.createEditFields();
  207. addContainerToInspector();
  208. }
  209. private void addContainerToInspector() {
  210. for (Container cell : cellsInRow) {
  211. InspectorTable.this.add(cell);
  212. }
  213. }
  214. public void setSelected(boolean value) {
  215. selectionBox.setSelected(value);
  216. // Color row
  217. for (Container cell : cellsInRow) {
  218. cell.setBackground(selectionBox.isSelected() ? selectedColor : Color.white);
  219. }
  220. }
  221. public boolean isSelected() {
  222. return selectionBox.isSelected();
  223. }
  224. private void createEditFields() {
  225. // Selected
  226. JPanel selectedColumnPanel = new JPanel(new BorderLayout());
  227. selectedColumnPanel.setBackground(Color.white);
  228. selectedColumnPanel.setBorder(BorderFactory.createLineBorder(borderColor));
  229. selectionBox = new JCheckBox();
  230. selectionBox.addActionListener(clicked -> {
  231. setSelected(selectionBox.isSelected());
  232. setSelectAllCheckBox();
  233. });
  234. selectedColumnPanel.setMinimumSize(new Dimension(columnHeight, columnHeight));
  235. selectedColumnPanel.setPreferredSize(new Dimension(columnHeight, columnHeight));
  236. selectedColumnPanel.setMaximumSize(new Dimension(columnHeight, columnHeight));
  237. selectionBox.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
  238. selectionBox.setOpaque(false);
  239. selectedColumnPanel.add(selectionBox, BorderLayout.CENTER);
  240. cellsInRow[0] = selectedColumnPanel;
  241. // ObjectName and ID
  242. JTextField objectNameTextField = new JTextField(this.element.parentObject.getName());
  243. objectNameTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
  244. this.element.parentObject.setName(objectNameTextField.getText());
  245. });
  246. objectNameTextField.addActionListener(ae -> update_ui());
  247. cellsInRow[1] = objectNameTextField;
  248. JTextField idObjectTextField = new JTextField(Integer.toString(this.element.parentObject.getId()));
  249. idObjectTextField.setMinimumSize(idObjectTextField.getPreferredSize());
  250. idObjectTextField.setBackground(Color.white);
  251. idObjectTextField.setEditable(false);
  252. idObjectTextField.setEnabled(false);
  253. cellsInRow[2] = idObjectTextField;
  254. // Name
  255. JTextField elementNameTextField = new JTextField(this.element.getEleName());
  256. elementNameTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
  257. this.element.setEleName(elementNameTextField.getText());
  258. });
  259. elementNameTextField.setBackground(Color.white);
  260. cellsInRow[3] = elementNameTextField;
  261. // Energy
  262. JFormattedTextField energyTextField = new JFormattedTextField(doubleFormatter);
  263. energyTextField.setInputVerifier(getInputVerifier());
  264. energyTextField.setValue(this.element.getEnergy());
  265. energyTextField.setBackground(Color.white);
  266. energyTextField.addPropertyChangeListener(actionEvent -> {
  267. try {
  268. float energy = Float.parseFloat(energyTextField.getText());
  269. if (this.element.getEnergy() != energy) {
  270. this.element.setEnergyPerElement(energy);
  271. control.calculateStateAndVisualForCurrentTimeStep();
  272. }
  273. } catch (NumberFormatException e) {
  274. // Dont Update
  275. }
  276. });
  277. cellsInRow[4] = energyTextField;
  278. // Priority
  279. JComboBox<Priority> comboBox = new JComboBox<Priority>(Priority.values());
  280. comboBox.setSelectedItem(this.element.getPriority());
  281. comboBox.setBackground(Color.white);
  282. comboBox.setEditable(false);
  283. comboBox.addActionListener(ae -> {
  284. this.element.setPriority((Priority) comboBox.getSelectedItem());
  285. });
  286. cellsInRow[5] = comboBox;
  287. // Active Delete Column
  288. JPanel checkBoxWrapperPanel = new JPanel(new BorderLayout());
  289. checkBoxWrapperPanel.setBorder(BorderFactory.createLineBorder(borderColor));
  290. checkBoxWrapperPanel.setBackground(Color.white);
  291. checkBoxWrapperPanel.setMinimumSize(new Dimension(columnHeight, columnHeight));
  292. checkBoxWrapperPanel.setMaximumSize(new Dimension(columnHeight, columnHeight));
  293. // Active
  294. JCheckBox checkbox = new JCheckBox();
  295. checkbox.setSelected(this.element.isActive());
  296. checkbox.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
  297. checkbox.setOpaque(false);
  298. checkbox.addActionListener(actionEvent -> {
  299. this.element.setActive(checkbox.isSelected());
  300. control.calculateStateAndVisualForCurrentTimeStep();
  301. });
  302. checkBoxWrapperPanel.add(checkbox, BorderLayout.CENTER);
  303. cellsInRow[6] = checkBoxWrapperPanel;
  304. }
  305. }
  306. }