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.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.Collection;
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 JPopupMenu btnAddPopUp = new JPopupMenu("New");
private final JButton btnAdd = new JButton(new ImageIcon(Import.loadImage(ImagePreference.Category.Add, 16, 16)));
private final JButton btnDel = new JButton(new ImageIcon(Import.loadImage(ImagePreference.Category.Delete, 16, 16)));
private final JToolBar toolBar = new JToolBar();
private final JMenuItem mItemNew = new JMenuItem("New..");
private final JMenuItem mItemCategory = new JMenuItem("Category");
private final JMenuItem mItemObject = new JMenuItem("Object");
private final JMenuItem mItemSwitch = new JMenuItem("Switch");
private final JTree categoryTree = new JTree();
public CategoryPanel(Control control, Gui gui) {
this.control = control;
this.gui = gui;
init();
updateCategories(GuiSettings.getCategories());
control.OnCategoryChanged.addListener(() -> this.updateCategories(GuiSettings.getCategories()));
}
private void init() {
this.setMinimumSize(new Dimension(200, 200));
toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
toolBar.setFloatable(false);
initLayout();
initButtons();
categoryTree.setCellRenderer(new CategoryTreeRenderer());
categoryTree.setRowHeight(NODE_SIZE);
CategoryMouseListener mouseListener = new CategoryMouseListener();
categoryTree.addMouseListener(mouseListener);
categoryTree.addMouseMotionListener(mouseListener);
setColumnHeaderView(buttonPanel);
setViewportView(categoryTree);
}
private void initLayout(){
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
btnAddPopUp.add(mItemNew);
btnAddPopUp.addSeparator();
btnAddPopUp.add(mItemCategory);
btnAddPopUp.add(mItemObject);
btnAddPopUp.add(mItemSwitch);
toolBar.add(btnAdd);
toolBar.add(btnDel);
buttonPanel.add(toolBar);
}
private void initButtons(){
mItemNew.addActionListener(clicked -> new CreateNewDialog(control, gui));
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));
btnAdd.addActionListener(clicked -> btnAddPopUp.show(btnAdd, -1, +20));
btnDel.addActionListener(clicked -> TryDeleteSelectedCategory());
btnAdd.setToolTipText("New
Add a new Category or Item to the library.");
btnDel.setToolTipText("Delete
Removes a Category or a Category Item.");
}
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."));
}
/**
* When changes are made to the Categories.
*
* @param categories the Categories
*/
private void updateCategories(Collection categories) {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Categories");
categories.stream().map(CategoryTreeNode::new).forEach(root::add);
categoryTree.setModel(new DefaultTreeModel(root));
}
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.setForeground(ColorPreference.Category.Focus);
label.setOpaque(true);
}
return label;
}
}
private class CategoryMouseListener extends MouseAdapter{
AbstractCanvasObject selected = null;
@Override
public void mousePressed(MouseEvent e) {
Optional selectedNode = Optional.ofNullable(
(DefaultMutableTreeNode) categoryTree.getLastSelectedPathComponent());
selectedNode.ifPresent(node -> {
int depthOfNode = node.getLevel();
if (depthOfNode != 2) {
return;
}
ObjectTreeNode objectNode = (ObjectTreeNode) node;
selected = objectNode.getObject();
log.info("Test" + selected);
Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(Import.loadImage(selected.getImagePath(), 32, 32), new Point(),
"Image");
gui.setCursor(cursor);
});
}
@Override
public void mouseReleased(MouseEvent e) {
if(selected == null){
return;
}
gui.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
Canvas groupNodeCanvas = gui.getCanvas();
Optional positionInCanvas = Optional.ofNullable(groupNodeCanvas.getMousePosition());
AbstractCanvasObject finalTempCps = selected;
final int halfCursorSize = GuiSettings.getPictureScaleDiv2();
positionInCanvas.ifPresent(pos -> {
AbstractCanvasObject obj = null;
if (finalTempCps instanceof HolonObject hO) {
obj = new HolonObject(hO);
obj.setPosition(pos.x + halfCursorSize, pos.y + halfCursorSize);
} else if (finalTempCps instanceof HolonSwitch sw) {
obj = new HolonSwitch(sw);
obj.setPosition(pos.x + halfCursorSize, pos.y + halfCursorSize);
}
control.addObjectOnCanvas(groupNodeCanvas.getGroupNode(), obj);
control.calculateStateAndVisualForCurrentTimeStep();
});
selected = null;
}
}
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;
}
}
}