-
Notifications
You must be signed in to change notification settings - Fork 0
/
CategoryViewEditor.java
277 lines (238 loc) · 9.2 KB
/
CategoryViewEditor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
package com.barattoManager.ui.components;
import com.barattoManager.category.Category;
import com.barattoManager.category.CategoryManager;
import com.barattoManager.category.field.Field;
import com.barattoManager.exception.CategoryAlreadyExist;
import com.barattoManager.exception.FieldAlreadyExist;
import com.barattoManager.exception.NoNodeSelected;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Objects;
public class CategoryViewEditor extends JPanel {
private static final Dimension DIMENSION = new Dimension(500, 290);
public static final String ICON_CATEGORY_OPEN = "/icon/category_open.png";
public static final String ICON_CATEGORY_CLOSE = "/icon/category_close.png";
public static final String ICON_CATEGORY_FIELD = "/icon/category_field.png";
private final JTree tree;
private final DefaultTreeModel treeModel;
private final CategoryManager categoryManager;
public CategoryViewEditor() {
categoryManager = CategoryManager.getInstance();
var root = new DefaultMutableTreeNode("Categorie");
tree = createTree(root);
tree.setRootVisible(true);
treeModel = (DefaultTreeModel) tree.getModel();
// Add the JTree in the JPanel
add(new JScrollPane(tree)).setPreferredSize(DIMENSION);
// Add button
makeButtons();
}
/**
* Method used to create a JTree based oh the category
*
* @return {@link JTree} object
*/
private JTree createTree(DefaultMutableTreeNode root) {
for (Category cat : categoryManager.getCategoryMap().values()) {
var node = createCategoryNode(cat, root);
getSubCategory(cat, node);
}
// Create teh tree based on rootNode
var treeTmp = new JTree(root);
// Change the default JTree icons
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) treeTmp.getCellRenderer();
renderer.setClosedIcon(new ImageIcon(Objects.requireNonNull(this.getClass().getResource(ICON_CATEGORY_OPEN))));
renderer.setOpenIcon(new ImageIcon(Objects.requireNonNull(this.getClass().getResource(ICON_CATEGORY_CLOSE))));
renderer.setLeafIcon(new ImageIcon(Objects.requireNonNull(this.getClass().getResource(ICON_CATEGORY_FIELD))));
return treeTmp;
}
/**
* Method used to create the button bar
*/
private void makeButtons() {
var panel = new JPanel();
// Buttons
var newCategoryButton = new JButton("Nuova Categoria Radice");
var newSubcategoryButton = new JButton("Nuova Sotto-Categoria");
var newFieldButton = new JButton("Aggiungi nuovo campo");
// Button Listener
newSubcategoryButton.addActionListener(e -> {
TreeNode[] nodePath;
try {
// Get the selected node
nodePath = getSelectedPathNode();
var categoryInputPanel = new NewCategoryPanel();
int result = JOptionPane.showOptionDialog(
this,
categoryInputPanel,
"Creazione di una sotto-categoria",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
null,
null
);
if (result == JOptionPane.OK_OPTION) {
assert nodePath != null;
var newSubCategory = categoryManager.addNewSubCategory(
treeNodeArrayToArrayList(nodePath),
categoryInputPanel.getCategoryName().getText(),
categoryInputPanel.getCategoryDescription().getText());
paintNewCategory(newSubCategory);
}
} catch (NoNodeSelected | CategoryAlreadyExist ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(), "Errore", JOptionPane.ERROR_MESSAGE);
}
});
newFieldButton.addActionListener(e -> {
TreeNode[] nodePath;
try {
// Get the selected node
nodePath = getSelectedPathNode();
var fieldInputPanel = new NewFieldInput();
int result = JOptionPane.showOptionDialog(
this,
fieldInputPanel,
"Creazione di un nuovo campo",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
null,
null
);
if (result == JOptionPane.OK_OPTION) {
assert nodePath != null;
String fieldName = fieldInputPanel.getFieldName().getText();
var categoryOfNewField =categoryManager.addNewField(
treeNodeArrayToArrayList(nodePath),
fieldName,
fieldInputPanel.getFieldIsRequired().isSelected()
);
paintNewField(categoryOfNewField, fieldName);
}
} catch (NoNodeSelected | FieldAlreadyExist ex) {
JOptionPane.showMessageDialog(this, ex.getMessage(), "Errore", JOptionPane.ERROR_MESSAGE);
}
});
// Add buttons to panel
panel.add(newCategoryButton);
panel.add(newSubcategoryButton);
panel.add(newFieldButton);
// Add panel to the main
add(panel, BorderLayout.SOUTH);
}
/**
* Method used to paint in the {@link #tree} a new category (Category + Fields).
* @param category {@link Category} to paint in the {@link #tree}
*/
private void paintNewCategory(Category category) {
// Print the new category
var newCategoryNode = new DefaultMutableTreeNode(("%s ~ %s").formatted(category.getName(), category.getDescription()));
var selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
insertNewNodeAndUpdate(newCategoryNode, selectedNode);
// Print the Fields
for(Field field: category.getCategoryFields().values()) {
var newFieldNode = new DefaultMutableTreeNode("%s: %s".formatted(field.getName(), field.isRequired()));
insertNewNodeAndUpdate(newFieldNode, newCategoryNode);
}
}
/**
* Method used to paint in the {@link #tree} a new field.
* @param category {@link Category} to start adding the new field
* @param newFieldName Field Name
*/
private void paintNewField(Category category, String newFieldName) {
var field = category.getCategoryFields().get(newFieldName.toLowerCase());
var newFieldNode = new DefaultMutableTreeNode(("%s: %s").formatted(field.getName(), field.isRequired()));
var selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
insertNewNodeAndUpdate(newFieldNode, selectedNode);
addFieldNodes(newFieldNode, selectedNode);
}
private void addFieldNodes(DefaultMutableTreeNode newFieldNode, DefaultMutableTreeNode node) {
if (node.getChildCount() != 0) {
for (int i = 0; i < node.getChildCount(); i++) {
var subNode = node.getChildAt(i);
if (!subNode.isLeaf()) {
insertNewNodeAndUpdate(newFieldNode, (DefaultMutableTreeNode) subNode);
}
addFieldNodes(newFieldNode, (DefaultMutableTreeNode) subNode);
}
}
else {
if (!node.isLeaf()) {
insertNewNodeAndUpdate(newFieldNode, node);
}
}
}
/**
* Method used to insert a new nope on the fly and update the view of tree.
* @param nodeToAdd Node to add in the {@link #tree}
* @param fatherNode Node that's the father of new node.
*/
private void insertNewNodeAndUpdate(DefaultMutableTreeNode nodeToAdd, DefaultMutableTreeNode fatherNode) {
treeModel.insertNodeInto(nodeToAdd, fatherNode, fatherNode.getChildCount());
treeModel.reload(nodeToAdd);
TreeNode[] CategoryNodes = treeModel.getPathToRoot(nodeToAdd);
var CategoryPath = new TreePath(CategoryNodes);
tree.scrollPathToVisible(CategoryPath);
}
/**
* Method to convert and array of {@link TreeNode} in to an array of {@link String}
* @param nodePath Array of {@link TreeNode} to convert
* @return Array of {@link String}
*/
private ArrayList<String> treeNodeArrayToArrayList(TreeNode[] nodePath) {
var arrayList = new ArrayList<String>();
for (TreeNode node: nodePath) {
// Split the category name and description and take only the category name
arrayList.add(node.toString().split("~")[0].trim());
}
return arrayList;
}
/**
* Method used to get the current selected node in the {@link #tree}.
* @return Array of {@link TreeNode} that contains the node path.
* @throws NoNodeSelected is thrown if the user does not select any node.
*/
private TreeNode[] getSelectedPathNode() throws NoNodeSelected {
var selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (selectedNode == null) {
throw new NoNodeSelected("Non è stato selezionata nessuna categoria. Seleziona una categoria e riprova.");
}
else {
return selectedNode.getPath();
}
}
/**
* Recursive method used to append the sub category
*
* @param cat Category that want append in the tree
* @param catAdd Node of the tree where teh category will be appended.
*/
private void getSubCategory(Category cat, DefaultMutableTreeNode catAdd) {
if (!cat.getSubCategory().isEmpty()) {
for (Category subCat : cat.getSubCategory().values()) {
DefaultMutableTreeNode node = createCategoryNode(subCat, catAdd);
getSubCategory(subCat, node);
}
}
}
/**
* Method used to create a complete (category + field) node.
* @param category {@link Category} want to create the node.
* @param fatherNode {@link DefaultMutableTreeNode} node to attach the new category node
* @return {@link DefaultMutableTreeNode} New category node
*/
private DefaultMutableTreeNode createCategoryNode(Category category, DefaultMutableTreeNode fatherNode) {
// Add the category
var node = new DefaultMutableTreeNode(("%s ~ %s").formatted(category.getName(), category.getDescription()));
fatherNode.add(node);
// Add fields
for (Field categoryField: category.getCategoryFields().values()) {
node.add(new DefaultMutableTreeNode(("%s: %s").formatted(categoryField.getName(), categoryField.isRequired())));
}
return node;
}
}