package holeg.ui.view.category; import holeg.model.AbstractCanvasObject; import holeg.model.HolonObject; import holeg.model.HolonSwitch; import holeg.preferences.ColorPreference; import holeg.preferences.ImagePreference; import holeg.ui.controller.Control; import holeg.ui.model.GuiSettings; import holeg.ui.view.canvas.Canvas; import holeg.ui.view.dialog.AddObjectPopUp; import holeg.ui.view.dialog.CreateNewDialog; import holeg.ui.view.image.Import; import holeg.ui.view.main.Gui; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Objects; import java.util.Optional; import java.util.logging.Logger; public class CategoryPanel extends JScrollPane { private static final Logger log = Logger.getLogger(CategoryPanel.class.getName()); private final static int NODE_SIZE = 25; private final Control control; private final Gui gui; private final JPanel buttonPanel = new JPanel(); // Buttons private final JMenuItem mItemCategory = new JMenuItem("Category"); private final JMenuItem mItemObject = new JMenuItem("Object"); private final JMenuItem mItemSwitch = new JMenuItem("Switch"); private final JPopupMenu contextMenu = new JPopupMenu(); private final JMenu newMenu = new JMenu("New"); private final JMenuItem editItem = new JMenuItem("Edit Object"); private final JMenuItem removeItem = new JMenuItem("Remove"); private final JTree categoryTree = new JTree(); public CategoryPanel(Control control, Gui gui) { this.control = control; this.gui = gui; init(); updateCategories(); control.OnCategoryChanged.addListener(this::updateCategories); } private void init() { this.setMinimumSize(new Dimension(200, 200)); initLayout(); initButtons(); initContextHandle(); categoryTree.setCellRenderer(new CategoryTreeRenderer()); categoryTree.setRowHeight(NODE_SIZE); CategoryMouseListener mouseListener = new CategoryMouseListener(); categoryTree.addMouseListener(mouseListener); categoryTree.addMouseMotionListener(mouseListener); setColumnHeaderView(buttonPanel); setViewportView(categoryTree); categoryTree.setFocusable(false); this.setFocusable(false); } private void initContextHandle() { contextMenu.add(newMenu); contextMenu.add(editItem); contextMenu.add(removeItem); newMenu.add(mItemCategory); newMenu.add(mItemObject); newMenu.add(mItemSwitch); editItem.addActionListener(clicked -> getSelectedNode().ifPresent(node -> { ObjectTreeNode objectNode = (ObjectTreeNode) node; new AddObjectPopUp(control, objectNode.getObject(), objectNode.getCategory(), gui); })); removeItem.addActionListener(clicked -> getSelectedNode().ifPresent(selectedNode -> { if (selectedNode instanceof CategoryTreeNode node) { GuiSettings.getCategories().remove(node.category); } else if (selectedNode instanceof ObjectTreeNode node) { node.getCategory().getObjects().remove(node.getObject()); } updateCategories(); })); categoryTree.setComponentPopupMenu(contextMenu); } private void initLayout() { buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS)); } private void initButtons() { mItemCategory.addActionListener(clicked -> new CreateNewDialog(control, CreateNewDialog.Option.Category, gui)); mItemObject.addActionListener(clicked -> new CreateNewDialog(control, CreateNewDialog.Option.Object, gui)); mItemSwitch.addActionListener(clicked -> new CreateNewDialog(control, CreateNewDialog.Option.Switch, gui)); } private void TryDeleteSelectedCategory() { Optional selectedNode = Optional.ofNullable((DefaultMutableTreeNode) categoryTree.getLastSelectedPathComponent()); selectedNode.ifPresentOrElse(node -> { if (node instanceof CategoryTreeNode catNode) { int dialogResult = JOptionPane.showConfirmDialog(gui, "Do you really want to delete the Category " + catNode + "?", "Warning", JOptionPane.YES_NO_OPTION); if (dialogResult == JOptionPane.YES_OPTION) { GuiSettings.getCategories().stream().filter(cat -> Objects.equals(cat.getName(), catNode.toString())).findAny() .ifPresent(control::deleteCategory); } } else if (node instanceof ObjectTreeNode objNode) { objNode.getCategory().getObjects().remove(objNode.object); } categoryTree.repaint(); }, () -> JOptionPane.showMessageDialog(gui, "Please select a Category or an Object in the left library in order to delete something.")); } private void updateCategories() { categoryTree.setModel(generateCategoryModel()); } private DefaultTreeModel generateCategoryModel(){ DefaultMutableTreeNode root = new DefaultMutableTreeNode("Categories"); GuiSettings.getCategories().stream().map(CategoryTreeNode::new).forEach(root::add); return new DefaultTreeModel(root); } private Optional getSelectedNode() { return Optional.ofNullable((DefaultMutableTreeNode) categoryTree.getLastSelectedPathComponent()); } private static class CategoryTreeRenderer implements TreeCellRenderer { @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { JLabel label = new JLabel(value.toString()); if (value instanceof CategoryTreeNode) { label.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Category.Folder))); } else if (value instanceof ObjectTreeNode node) { Image image = Import.loadImage(node.getObject().getImagePath(), tree.getRowHeight(), tree.getRowHeight()); label.setIcon(new ImageIcon(image)); } if (hasFocus) { label.setBackground(ColorPreference.Category.Focus); label.setOpaque(true); } return label; } } private static class CategoryTreeNode extends DefaultMutableTreeNode { private final Category category; public CategoryTreeNode(Category category) { super(category.getName()); this.category = category; category.getObjects().stream().map(obj -> new ObjectTreeNode(category, obj)).forEach(this::add); } public Category getCategory() { return category; } } private static class ObjectTreeNode extends DefaultMutableTreeNode { private final AbstractCanvasObject object; private final Category category; public ObjectTreeNode(Category category, AbstractCanvasObject object) { super(object.getName()); this.category = category; this.object = object; } public AbstractCanvasObject getObject() { return object; } public Category getCategory() { return category; } } private class CategoryMouseListener extends MouseAdapter { AbstractCanvasObject selected = null; @Override public void mousePressed(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e)) { preparePopUpMenu(e); return; } getSelectedNode().ifPresent(node -> { if (node.getLevel() != 2) { return; } ObjectTreeNode objectNode = (ObjectTreeNode) node; selected = objectNode.getObject(); Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(Import.loadImage(selected.getImagePath(), 32, 32), new Point(), "Image"); gui.setCursor(cursor); }); } private void preparePopUpMenu(MouseEvent e) { categoryTree.setSelectionPath(categoryTree.getPathForLocation(e.getX(), e.getY())); getSelectedNode().ifPresent(selectedNode -> { if (selectedNode instanceof CategoryTreeNode) { mItemObject.setVisible(true); mItemSwitch.setVisible(true); editItem.setVisible(false); removeItem.setVisible(true); } else if (selectedNode instanceof ObjectTreeNode) { mItemSwitch.setVisible(true); mItemObject.setVisible(true); editItem.setVisible(true); removeItem.setVisible(true); }else{ mItemObject.setVisible(false); mItemSwitch.setVisible(false); editItem.setVisible(false); removeItem.setVisible(false); } }); } @Override public void mouseReleased(MouseEvent e) { if (selected == null) { return; } gui.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); Canvas groupNodeCanvas = gui.getActualCanvas(); Optional positionInCanvas = Optional.ofNullable(groupNodeCanvas.getMousePosition()); AbstractCanvasObject selectedObj = selected; selected = null; final int halfCursorSize = GuiSettings.getPictureScaleDiv2(); positionInCanvas.ifPresent(pos -> { AbstractCanvasObject obj; if (selectedObj instanceof HolonObject hO) { obj = new HolonObject(hO); } else if (selectedObj instanceof HolonSwitch sw) { obj = new HolonSwitch(sw); }else { return; } obj.setPosition(pos.x + halfCursorSize, pos.y + halfCursorSize); control.addObjectOnCanvas(groupNodeCanvas.getGroupNode(), obj); control.calculateStateAndVisualForCurrentTimeStep(); }); } } }