package holeg.ui.view.main;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.File;
import java.net.URI;
import java.util.Collection;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import holeg.interfaces.LocalMode;
import holeg.model.AbstractCanvasObject;
import holeg.model.GroupNode;
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.model.IdCounter;
import holeg.model.Model;
import holeg.model.Model.FairnessModel;
import holeg.ui.view.canvas.Canvas;
import holeg.ui.view.component.ButtonTabComponent;
import holeg.ui.view.dialog.AboutUsPopUp;
import holeg.ui.view.dialog.AddObjectPopUp;
import holeg.ui.view.dialog.CanvasResizePopUp;
import holeg.ui.view.dialog.CreateNewDialog;
import holeg.ui.view.dialog.CreateNewDialog.Option;
import holeg.ui.view.dialog.EditEdgesPopUp;
import holeg.ui.view.information.HolonInformationPanel;
import holeg.ui.view.inspector.Inspector;
import holeg.ui.view.inspector.UnitGraph;
import holeg.ui.view.window.AddOnWindow;
import holeg.ui.view.window.FlexWindow;
import holeg.ui.view.window.Outliner;
import holeg.ui.view.image.Import;
/**
* Graphical User Interface.
*
* @author Gruppe14
*/
public class GUI {
private static final Logger log = Logger.getLogger(Model.class.getName());
/**
* Menu on the Top containing File, Edit View Help etc
*/
private final JMenuBar menuBar = new JMenuBar();
private final JMenu mnNewMenu = new JMenu("File");
private final JMenu mnNewMenuEdit = new JMenu("Edit");
private final JMenu mnNewMenuOptions = new JMenu("Options");
private final JMenu mnNewMenuView = new JMenu("View");
private final JMenu menuWindow = new JMenu("Window");
/** Help Menu containing helpful Informations and the AboutUs Popup */
private final JMenu mnHelp = new JMenu("Help");
/**
* Help -> Introduction A small Introduction of the Application, SmartGrids and
* Holons
*/
private final JMenuItem mntmIntroduction = new JMenuItem("Introduction");
/**
* Help -> UserManual
*/
private final JMenuItem mntmUserManual = new JMenuItem("User Manual");
/** Help -> Algorithm Help Menu */
private final JMenuItem mntmAlgorithmHelp = new JMenuItem("Algorithm Introduction");
/** Help -> CodeDocumentation */
private final JMenuItem mntmCodeDoc = new JMenuItem("Code Documentation");
/** Help -> AboutUs */
private final JMenuItem mntmAboutUs = new JMenuItem("About Us");
/** checked if supplyBars should be shown */
private final JCheckBoxMenuItem showSupplyBarsCheckBox = new JCheckBoxMenuItem("Show supply bars.");
/** menu for the different fairness Models */
private final JMenu mnFairnessModel = new JMenu("Fairness Model");
/** press to supply minimum demand first */
private final JMenuItem mntmFairMinFirst = new JMenuItem("Minimum demand first");
/** press to give everyone the same energy */
private final JMenuItem mntmFairAlleEqual = new JMenuItem("Equal supply for everyone");
private final JMenuItem mntmOpen = new JMenuItem("Open");
private final JMenuItem mntmNew = new JMenuItem("New");
private final JMenuItem mntmSave = new JMenuItem("Save");
private final JMenuItem mntmCanvasSize = new JMenuItem("Set View Size");
private final JSplitPane splitPane = new JSplitPane();
private final JSplitPane splitPane1 = new JSplitPane();
// the tabbed canvas containing the different sub-net tabs of the grid (Main
// Grid + Nodes of Nodes)
private final JPanel myPanel = new JPanel(new BorderLayout());
private final JTabbedPane tabbedPaneInnerOriginal = new JTabbedPane(JTabbedPane.TOP);
// the main canvas where we can see the grid currently displayed
private final JScrollPane canvasSP = new JScrollPane();
private final JScrollPane scrollPane1 = new JScrollPane();
// private final JScrollPane holonSP = new JScrollPane();
// the original tabbed Pane (containing tabs for view, statistics, holon,
// flexibility)
private final JTabbedPane tabbedPaneOriginal = new JTabbedPane(JTabbedPane.TOP);
private final JPopupMenu popmenuEdit = new JPopupMenu();
private final JMenuItem editItem = new JMenuItem("Edit Object");
private final JLabel elementGraph = new JLabel("None ");
private final JTree categoryTree = new JTree();
/******************************************
************* Right Container*************
******************************************
* Right Container: here comes the information about the HolonObject, such as
* HolonElements Information, Properties and Consumption/Production graph.
**/
private final Inspector inspector;
private final HolonInformationPanel informationPanel;
private final JSplitPane splitHolonElPro = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
// Prechoosed local Periods
private final JScrollPane scrollProperties = new JScrollPane();
// In this section is the graph for the selected HolonElement of the clicked
private final Model model;
private final Control control;
// In this section are all the Holonelements that correspond to the clicked
// HolonObject with consumption/production, name and amount.
private final JPanel panel = new JPanel();
private final JPanel panelHolonEl = new JPanel();
// Buttons
private final JButton btnAdd = new JButton();
private final JPopupMenu btnAddPopUp = new JPopupMenu("Newacac");
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 JButton btnDel = new JButton();
private final JToolBar toolBar = new JToolBar();
private final JToolBar toolBarHolonEl = new JToolBar();
// Languages
private Canvas canvas;
private final UnitGraph unitGraph;
/** Textfield to show the period of an element */
private final JTextField unitGraphLocalPeriod = new JTextField(6);
private final JMenuItem mntmUndo = new JMenuItem("Undo");
private final JMenuItem mntmRedo = new JMenuItem("Redo");
private final JMenuItem mntmEditEdges = new JMenuItem("Edge Properties");
private final JMenuItem mntmAlignAll = new JMenuItem("Align All");
private final JMenuItem mntmResetCategory = new JMenuItem("Reset Categories");
// TODO(Tom2021-12-1) make GUI a JFRAME and remove holegJFrame
private JFrame holegJFrame;
// tabbedPaneOriginal or tabbedPaneSplit
private JTabbedPane tabTemp;
private String catOfObjToBeEdited;
private Canvas unc;
private JPanel contentPane;
// Pop up Windows
private AddObjectPopUp addObjectPopUP;
private AboutUsPopUp aboutUsPopUp;
// variables
private boolean dragging = false;
private String actualObjectClicked;
private Image img = null;
private AbstractCanvasObject tempCps = null;
// Time Stuff
private TimePanel timePanel;
public TimePanel getTimePanel() {
return timePanel;
}
private AbstractCanvasObject temp = null;
private String warningText = "Warning";
private String saveBeforeNew = "Do you want to save your current data?";
private String eraseCategory = "Do you really want to delete the Category ";
private String selectObjBeforeErase = "Please select a Category or an Object in the left library in order to delete something.";
private JMenuItem removeItem = new JMenuItem("Remove");
// Save / Load
private final JFileChooser safeLoadFileChooser = initSaveLoadFileChooser();
/**
* Create the application.
*
* @param control the Controller
*/
GUI(Control control) {
this.control = control;
this.informationPanel = new HolonInformationPanel(control);
this.model = control.getModel();
inspector = new Inspector(control);
control.calculateStateAndVisualForCurrentTimeStep();
this.unitGraph = new UnitGraph(control);
this.canvas = new Canvas(control, model.getCanvas());
initialize();
updateCategories(GuiSettings.getCategories());
control.OnCategoryChanged.addListener(() -> this.updateCategoryUI(GuiSettings.getCategories()));
this.unc = this.canvas;
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
holegJFrame = new JFrame();
holegJFrame.setTitle("HOLEG Simulator");
holegJFrame.setBounds(new Rectangle(1200, 800));
//Center
holegJFrame.setLocationRelativeTo(null);
holegJFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
holegJFrame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
if (JOptionPane.showConfirmDialog(holegJFrame, "Are you sure you want to exit?", "HOLEG",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
//TODO(Tom2022-01-27):
System.exit(0);
}
}
});
contentPane = (JPanel) holegJFrame.getContentPane();
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
InputMap inputMap = contentPane.getInputMap(condition);
ActionMap actionMap = contentPane.getActionMap();
String cntrlZDown = "controlZ";
inputMap.put(KeyStroke.getKeyStroke("control Z"), cntrlZDown);
actionMap.put(cntrlZDown, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
//TODO(Tom2022-01-27): CtrlZ
}
});
String cntrlYDown = "controlY";
inputMap.put(KeyStroke.getKeyStroke("control Y"), cntrlYDown);
actionMap.put(cntrlYDown, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
//TODO Ctrl Y
}
});
String cntrlADown = "controlA";
inputMap.put(KeyStroke.getKeyStroke("control A"), cntrlADown);
AbstractAction controlA = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
GuiSettings.getSelectedObjects().clear();
//TODO(Tom2022-01-27): Ctrl A
}
};
actionMap.put(cntrlADown, controlA);
String delDown = "delete";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0, false), delDown);
actionMap.put(delDown, new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
chooseTabTemp();
//TODO(Tom2022-01-27): delete
GuiSettings.getSelectedObjects().clear();
}
});
String cntrlCDown = "controlC";
inputMap.put(KeyStroke.getKeyStroke("control C"), cntrlCDown);
AbstractAction controlC = new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
chooseTabTemp();
JScrollPane scrollPane = getScrollPaneFromTabbedPane();
if (!GuiSettings.getSelectedObjects().isEmpty()) {
if (scrollPane.getViewport().getComponent(0)instanceof Canvas groupNodeCanvas)
control.copy(groupNodeCanvas.getGroupNode());
else
control.copy(null);
if (!GuiSettings.getClipboardObjects().isEmpty()) {
//TODO(Tom2022-01-14): old code changes itemPaste
//OLD: canvas.itemPaste.setEnabled(true);
}
}
}
};
actionMap.put(cntrlCDown, controlC);
String cntrlVDown = "controlV";
inputMap.put(KeyStroke.getKeyStroke("control V"), cntrlVDown);
AbstractAction controlV = new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
//TODO(Tom2022-01-27): Paste
}
};
actionMap.put(cntrlVDown, controlV);
String cntrlXDown = "controlX";
inputMap.put(KeyStroke.getKeyStroke("control X"), cntrlXDown);
AbstractAction controlX = new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
chooseTabTemp();
JScrollPane scrollPane = getScrollPaneFromTabbedPane();
if (!GuiSettings.getSelectedObjects().isEmpty()) {
if (scrollPane.getViewport().getComponent(0)instanceof Canvas groupNodeCanvas) {
control.cut(groupNodeCanvas.getGroupNode());
control.calculateStateAndVisualForCurrentTimeStep();
scrollPane.getViewport().getComponent(0).repaint();
} else {
control.cut(null);
control.calculateStateAndVisualForCurrentTimeStep();
log.info("canvas.repaint3");
canvas.repaint();
}
if (!GuiSettings.getClipboardObjects().isEmpty()) {
//TODO(Tom2022-01-14): old code changes itemPaste
//OLD: canvas.itemPaste.setEnabled(true);
}
}
}
};
actionMap.put(cntrlXDown, controlX);
holegJFrame.setJMenuBar(menuBar);
holegJFrame.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
menuBar.add(mnNewMenu);
mnNewMenu.add(mntmNew);
mnNewMenu.add(mntmOpen);
mnNewMenu.add(mntmSave);
menuBar.add(mnNewMenuEdit);
mnNewMenuEdit.add(mntmUndo);
mnNewMenuEdit.add(mntmRedo);
mnNewMenuEdit.add(mntmEditEdges);
mntmEditEdges.addActionListener(actionEvent -> {
EditEdgesPopUp edgePopUp = new EditEdgesPopUp(holegJFrame);
edgePopUp.setCanvas(canvas);
edgePopUp.setController(control);
edgePopUp.setVisible(true);
});
// Edit -> Align All
mnNewMenuEdit.add(mntmAlignAll);
mntmAlignAll.addActionListener(actionEvent -> {
// getScrollPaneFromTabbedPane().getViewport().getComponent(0) is always the
// active canvas
tryToAlignObjects();
});
menuBar.add(mnNewMenuOptions);
mnNewMenuOptions.add(mntmResetCategory);
mntmResetCategory.addActionListener(actionEvent -> {
control.resetCategories();
categoryTree.revalidate();
categoryTree.repaint();
});
/**
* Add Fairness Model Option to the option Menu
*/
mnNewMenuOptions.add(mnFairnessModel);
mnFairnessModel.add(mntmFairMinFirst);
mntmFairMinFirst.setForeground(Color.BLUE);
mntmFairMinFirst
.setToolTipText("HolonObjects with the smallest mininum Demand will be partially supplied first.\n"
+ "After that as many HolonObjects as possible will get fully supplied.");
mntmFairMinFirst.addActionListener(arg0 -> {
control.getModel().setFairnessModel(FairnessModel.MininumDemandFirst);
mntmFairMinFirst.setForeground(Color.BLUE);
mntmFairAlleEqual.setForeground(mnFairnessModel.getForeground());
control.calculateStateAndVisualForCurrentTimeStep();
// Update UpperNodes
Component canvasOrUpperNodeCanvas = getScrollPaneFromTabbedPane().getViewport().getComponent(0);
if (canvasOrUpperNodeCanvas != null && canvasOrUpperNodeCanvas instanceof Canvas groupNodeCanvas) {
groupNodeCanvas.repaint();
}
});
mnFairnessModel.add(mntmFairAlleEqual);
mntmFairAlleEqual.setToolTipText("HolonObjects will all get the same amount of energy.");
mntmFairAlleEqual.addActionListener(arg0 -> {
control.getModel().setFairnessModel(FairnessModel.AllEqual);
mntmFairAlleEqual.setForeground(Color.BLUE);
mntmFairMinFirst.setForeground(mnFairnessModel.getForeground());
control.calculateStateAndVisualForCurrentTimeStep();
// Update UpperNodes
Component canvasOrUpperNodeCanvas = getScrollPaneFromTabbedPane().getViewport().getComponent(0);
if (canvasOrUpperNodeCanvas != null && canvasOrUpperNodeCanvas instanceof Canvas groupNodeCanvas) {
groupNodeCanvas.repaint();
}
});
menuBar.add(mnNewMenuView);
mnNewMenuView.add(mntmCanvasSize);
mntmCanvasSize.addActionListener(actionEvent -> {
CanvasResizePopUp popUp = new CanvasResizePopUp(model, control, canvas, this.tabbedPaneInnerOriginal,
holegJFrame);
popUp.setVisible(true);
});
tabbedPaneInnerOriginal.addChangeListener(change -> {
control.clearSelection();
});
mnNewMenuView.add(mntmCanvasSize);
/*
* Adds Checkbox to turn supply bars on/off
*/
mnNewMenuView.add(showSupplyBarsCheckBox);
showSupplyBarsCheckBox.setSelected(true);
showSupplyBarsCheckBox.addActionListener(arg0 -> {
GuiSettings.showSupplyBars = showSupplyBarsCheckBox.isSelected();
log.info("canvas.repaint4");
canvas.repaint();
// Update UpperNodes
JScrollPane spane = getScrollPaneFromTabbedPane();
if (spane != null) {
Component canvasOrUpperNodeCanvas = spane.getViewport().getComponent(0);
if (canvasOrUpperNodeCanvas != null
&& canvasOrUpperNodeCanvas instanceof Canvas groupNodeCanvas) {
groupNodeCanvas.repaint();
}
}
});
initWindowMenu();
/**
* add Help Menu and its items
*/
menuBar.add(mnHelp);
mnHelp.add(mntmIntroduction);
mnHelp.add(mntmUserManual);
mnHelp.add(mntmAlgorithmHelp);
mnHelp.add(mntmCodeDoc);
mnHelp.add(mntmAboutUs);
canvas.setBackground(Color.WHITE);
canvas.setPreferredSize(new Dimension(GuiSettings.canvasSize.getX(), GuiSettings.canvasSize.getY()));
/********************
* RIGHT CONTAINER (INFORMATION)
**********************/
panelHolonEl.setLayout(new BoxLayout(panelHolonEl, BoxLayout.X_AXIS));
toolBarHolonEl.setFloatable(false);
panelHolonEl.add(toolBarHolonEl);
/***********************
* HolonElement Graph Actions
**********************/
/*
* Update Local Period of an Element Graph
*/
unitGraphLocalPeriod.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
try {
int localLength = Integer.parseInt(unitGraphLocalPeriod.getText());
unitGraphLocalPeriod.setBackground(Color.WHITE);
/**
* set local graph Period
*/
if (e.getKeyCode() == KeyEvent.VK_ENTER){
LocalMode.Period period = new LocalMode.Period(localLength);
period.setInterval(localLength);
unitGraph.setPeriod(period);
}
} catch (NumberFormatException ex) {
unitGraphLocalPeriod.setBackground(ColorPreference.GUI.PALE_RED);
}
}
});
/*****************************
* RIGHT CONTAINER DONE
*****************************/
holegJFrame.getContentPane().setLayout(new BorderLayout(0, 0));
/****************
* Tree Stuff
****************/
// Override Key Actions
inputMap = categoryTree.getInputMap();
inputMap.put(KeyStroke.getKeyStroke("control C"), cntrlCDown);
inputMap.put(KeyStroke.getKeyStroke("control V"), cntrlVDown);
inputMap.put(KeyStroke.getKeyStroke("control X"), cntrlXDown);
inputMap.put(KeyStroke.getKeyStroke("control A"), cntrlADown);
TreeCellRenderer customRenderer = new TreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
JLabel label = new JLabel();
Image imgR;
if (leaf) {
for (Category cat : GuiSettings.getCategories()) {
for (AbstractCanvasObject cps : cat.getObjects()) {
if (value.toString().equals(cps.getName())) {
imgR = Import.loadImage(cps.getImagePath(), 50, 50);
if (imgR != null) {
label.setIcon(new ImageIcon(imgR));
}
label.setText(cps.getName());
}
}
}
}
tree.setRowHeight(50);
if (hasFocus) {
label.setForeground(ColorPreference.Category.Focus);
label.setOpaque(true);
}
if (label.getText().isEmpty()) {
label.setText(value.toString());
if (!value.toString().equals("Categories")) {
label.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Category.Folder)));
}
}
return label;
}
};
categoryTree.setCellRenderer(customRenderer);
categoryTree.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
checkForDragAndDrop(e);
}
/**
* checks if an object of the current Panel could be replaced by the dragged
* object
*
* @param e
*/
private void checkForDragAndDrop(MouseEvent e) {
try {
/**
* if no object gets dragged -> finished
*/
if (!dragging)
return;
/**
* select the current Panel
*/
chooseTabTemp();
JScrollPane scrollPane = getScrollPaneFromTabbedPane();
if (scrollPane == null)
return;
Component canvasOrUpperNodeCanvas = scrollPane.getViewport().getComponent(0);
/**
* check for replacements on the canvas
*/
if (canvasOrUpperNodeCanvas instanceof Canvas groupNodeCanvas) {
if (unc.getMousePosition() == null)
return;
int x = (int) unc.getMousePosition().getX() + 16;
int y = (int) unc.getMousePosition().getY() + 16;
/**
* check for replacement
*/
groupNodeCanvas.checkForReplacement(x, y);
/**
* repaint
*/
unc.invalidate();
unc.repaint();
} else {
if (canvas.getMousePosition() == null)
return;
int x = (int) canvas.getMousePosition().getX() + 16;
int y = (int) canvas.getMousePosition().getY() + 16;
/**
* check for replacement
*/
canvas.checkForReplacement(x, y);
/**
* repaint
*/
log.info("canvas.repaint5");
canvas.repaint();
}
contentPane.updateUI();
} catch (Exception eex) {
eex.printStackTrace();
}
}
});
categoryTree.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
try {
if (dragging) {
chooseTabTemp();
JScrollPane scrollPane = getScrollPaneFromTabbedPane();
Component canvasOrUpperNodeCanvas = scrollPane.getViewport().getComponent(0);
if (canvasOrUpperNodeCanvas instanceof Canvas groupNodeCanvas) {
int x = (int) groupNodeCanvas.getMousePosition().getX() + 16;
int y = (int) groupNodeCanvas.getMousePosition().getY() + 16;
AbstractCanvasObject h = null;
if (tempCps instanceof HolonObject hO) {
h = new HolonObject(hO);
}
if (tempCps instanceof HolonSwitch sw) {
h = new HolonSwitch(sw);
}
h.setPosition(x, y);
control.addObjectCanvas(model.getCanvas(), h);
/**
* object would be replaced
*/
groupNodeCanvas.invalidate();
control.calculateStateAndVisualForCurrentTimeStep();
groupNodeCanvas.repaint();
} else {
int x = (int) canvas.getMousePosition().getX() + 16;
int y = (int) canvas.getMousePosition().getY() + 16;
AbstractCanvasObject h = null;
if (tempCps instanceof HolonObject hO) {
h = new HolonObject(hO);
}
if (tempCps instanceof HolonSwitch sw) {
h = new HolonSwitch(sw);
}
h.setPosition(x, y);
/**
* close UpperNodeTabs of replaced UpperNode
*/
//TODO(Tom2022-01-27):
control.addObjectCanvas(model.getCanvas(), h);
/**
* no object should get replaced
*/
log.info("canvas.repaint6");
canvas.repaint();
}
control.calculateStateAndVisualForCurrentTimeStep();
contentPane.updateUI();
dragging = false;
}
} catch (Exception eex) {
}
holegJFrame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});
popmenuEdit.add(editItem);
popmenuEdit.add(removeItem);
editItem.setEnabled(false);
editItem.addActionListener(actionEvent -> {
});
categoryTree.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
try {
actualObjectClicked = categoryTree.getPathForLocation(e.getX(), e.getY()).getLastPathComponent()
.toString();
// if an Object was selected, the porperties are shown in
// the table
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) categoryTree
.getPathForLocation(e.getX(), e.getY()).getLastPathComponent();
if (SwingUtilities.isRightMouseButton(e)) {
for (Category cat : GuiSettings.getCategories()) {
for (AbstractCanvasObject cps : cat.getObjects()) {
if (actualObjectClicked.equals(cps.getName())
&& !(cps instanceof HolonSwitch)) {
editItem.setEnabled(true);
popmenuEdit.show(e.getComponent(), e.getX(), e.getY());
catOfObjToBeEdited = selectedNode.getParent().toString();
tempCps = cps;
}
}
}
} else {
for (Category cat : GuiSettings.getCategories()) {
for (AbstractCanvasObject cps : cat.getObjects()) {
if (actualObjectClicked.equals(cps.getName())) {
File checkPath = new File(cps.getImagePath());
if (checkPath.exists()) {
img = new ImageIcon(cps.getImagePath()).getImage().getScaledInstance(32, 32,
java.awt.Image.SCALE_SMOOTH);
} else {
img = Import.loadImage(cps.getImagePath(), 32, 32);
}
tempCps = cps;
dragging = true;
Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(img, new Point(0, 0),
"Image");
holegJFrame.setCursor(cursor);
}
}
}
}
} catch (Exception eex) {
}
}
});
editItem.addActionListener(actionEvent -> {
// Remove the selected Object object
// AddObjectPopUp(boolean edit, AbstractCpsObject obj, String cat, JFrame
// parentFrame)
System.out.println("Edit");
addObjectPopUP = new AddObjectPopUp(true, tempCps, catOfObjToBeEdited, holegJFrame);
addObjectPopUP.setCategory(catOfObjToBeEdited);
addObjectPopUP.setController(control);
addObjectPopUP.setVisible(true);
});
removeItem.addActionListener(actionEvent -> {
// Remove the selected Object object
log.info("catOfObjToBeEdited:" + catOfObjToBeEdited + ", tempCps:" + tempCps);
control.findCategoryWithName(catOfObjToBeEdited).ifPresent(cat -> {
cat.removeObjectsWithName(tempCps.getName());
});
});
scrollPane1.setViewportView(categoryTree);
scrollPane1.setColumnHeaderView(panel);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
toolBar.setFloatable(false);
panel.add(toolBar);
btnAddPopUp.add(mItemNew);
mItemNew.addActionListener(actionEvent -> {
new CreateNewDialog(control, holegJFrame);
});
btnAddPopUp.addSeparator();
btnAddPopUp.add(mItemCategory);
mItemCategory.addActionListener(actionEvent -> {
new CreateNewDialog(control, Option.Category, holegJFrame);
});
btnAddPopUp.add(mItemObject);
mItemObject.addActionListener(actionEvent -> {
new CreateNewDialog(control, Option.Object, holegJFrame);
});
btnAddPopUp.add(mItemSwitch);
mItemSwitch.addActionListener(actionEvent -> {
new CreateNewDialog(control, Option.Switch, holegJFrame);
});
btnAdd.addActionListener(actionEvent -> btnAddPopUp.show(btnAdd, -1, +20));
btnAdd.setIcon(new ImageIcon(Import.loadImage("images/buttons/plus.png", 16, 16)));
btnAdd.setToolTipText("New
Add a new Category or Item to the library.");
toolBar.add(btnAdd);
/**
* Help Menu Action Listeners
*/
/**
* URL of the telecommunication git Wiki
*/
String tkWikiWebpage = "https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/";
/** open Introduction Web Page */
mntmIntroduction.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
openWebpage(tkWikiWebpage + "Introduction+V2.1");
}
});
/** open UserManual WebPage */
mntmUserManual.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
openWebpage(tkWikiWebpage + "User+Manual+V2.1");
}
});
/** open Algorithm Help Web Page */
mntmAlgorithmHelp.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
openWebpage(tkWikiWebpage + "Algorithms+V2.1");
}
});
/** open Code Documentation Web Page */
mntmCodeDoc.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
openWebpage(tkWikiWebpage + "Code+documentation+V2.1");
}
});
/**
* Pop up - About Us with some important information about the developers,
* source and programming stuff
*/
mntmAboutUs.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
aboutUsPopUp = new AboutUsPopUp(holegJFrame);
aboutUsPopUp.setVisible(true);
}
});
// Del Button
btnDel.addActionListener(actionEvent -> {
Object nodeInfo = categoryTree.getLastSelectedPathComponent();
if (nodeInfo != null) {
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) nodeInfo;
String nodeName = selectedNode.getUserObject().toString();
int depthOfNode = selectedNode.getLevel();
try {
switch (depthOfNode) {
case 1:
int dialogResult = JOptionPane.showConfirmDialog(holegJFrame, eraseCategory + nodeName + "?",
warningText, JOptionPane.YES_NO_OPTION);
if (dialogResult == JOptionPane.YES_OPTION) {
GuiSettings.getCategories().stream().filter(cat -> cat.getName() == nodeName).findAny()
.ifPresent(cat -> {
control.deleteCategory(cat);
});
}
break;
case 2:
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.getParent();
control.findCategoryWithName(parent.getUserObject().toString()).ifPresent(cat -> {
cat.removeObjectsWithName(nodeName);
});
break;
default:
JOptionPane.showMessageDialog(holegJFrame, selectObjBeforeErase);
}
} catch (Exception e2) {
}
} else {
JOptionPane.showMessageDialog(holegJFrame, selectObjBeforeErase);
}
categoryTree.repaint();
});
btnDel.setIcon(new ImageIcon(Import.loadImage("images/buttons/minus.png", 16, 16)));
btnDel.setToolTipText("Delete
Removes a Category or a Category Item.");
toolBar.add(btnDel);
holegJFrame.getContentPane().add(splitPane);
mntmNew.addActionListener(actionEvent -> {
if (model.getCanvas().getObjectsInThisLayer().findAny().isPresent()) {
int newWarning = JOptionPane.YES_NO_OPTION;
int dialogForNewWarning = JOptionPane.showConfirmDialog(holegJFrame, saveBeforeNew, warningText,
newWarning);
if (dialogForNewWarning == JOptionPane.YES_OPTION) {
mntmSave.doClick();
}
}
// Remove all but main tab
while (tabbedPaneInnerOriginal.getTabCount() > 1) {
tabbedPaneInnerOriginal.remove(1);
}
control.clearSelection();
model.clear();
control.OnSelectionChanged.broadcast();
GuiSettings.getSelectedEdges().clear();
control.getModel().setCurrentIteration(0);
elementGraph.setText("None");
log.info("canvas.repaint7");
canvas.repaint();
IdCounter.reset();
IdCounter.reset();
control.calculateStateAndVisualForCurrentTimeStep();
});
mntmOpen.addActionListener(clicked -> {
if(safeLoadFileChooser.showOpenDialog(this.holegJFrame) == JFileChooser.APPROVE_OPTION){
control.loadFile(safeLoadFileChooser.getSelectedFile());
//TODO(Tom2022-01-27): make better
this.canvas.setGroupNode(control.getModel().getCanvas());
this.canvas.repaint();
}
});
mntmSave.addActionListener(clicked -> {
log.info("Save Button Pressed");
if(safeLoadFileChooser.showSaveDialog(this.holegJFrame) == JFileChooser.APPROVE_OPTION){
String path = safeLoadFileChooser.getSelectedFile().getPath();
if(!path.endsWith(".json")){
path += ".json";
}
control.saveFile(new File(path));
}
});
mntmUndo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
menuUndoActionPerformed();
}
private void menuUndoActionPerformed() {
// try {
// control.loadAutoSave(control.getUndoSave());
//
// closeInvalidUpperNodeTabs();
//
// control.calculateStateAndVisualForCurrentTimeStep();
// log.info("canvas.repaint9");
// canvas.repaint();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
});
mntmRedo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
menuRedoActionPerformed();
}
private void menuRedoActionPerformed() {
// try {
// control.loadAutoSave(control.getRedoSave());
//
// closeInvalidUpperNodeTabs();
//
// control.calculateStateAndVisualForCurrentTimeStep();
// log.info("canvas.repaint10");
// canvas.repaint();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
});
timePanel = new TimePanel(control);
timePanel.setBorder(null);
timePanel.getTimeSlider().addChangeListener(changeEvent -> {
// TimeSliderChanged event
control.calculateStateAndVisualForTimeStep(timePanel.getTimeSlider().getValue());
unitGraph.repaint();
contentPane.updateUI();
});
splitPane1.setMinimumSize(new Dimension(0, 25));
splitPane.setRightComponent(splitPane1);
splitPane.setDividerLocation(200);
splitPane1.setDividerLocation(500);
splitPane.setLeftComponent(scrollPane1);
tabbedPaneOriginal.addTab("View", tabbedPaneInnerOriginal);
myPanel.add(canvasSP, BorderLayout.CENTER);
tabbedPaneInnerOriginal.addTab("Main Grid", myPanel);
splitPane1.setLeftComponent(tabbedPaneOriginal);
splitPane1.setRightComponent(splitHolonElPro);
splitPane1.setResizeWeight(0.9);
splitHolonElPro.setDividerLocation(700);
// containing the graph and the elements-list
splitHolonElPro.setTopComponent(inspector);
// containing the object's properties
splitHolonElPro.setBottomComponent(scrollProperties);
canvasSP.setViewportView(canvas);
// Set up of the Properties section
scrollProperties.setViewportView(this.informationPanel);
scrollProperties.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollProperties.getVerticalScrollBar().setUnitIncrement(16);
tabbedPaneOriginal.setBorder(null);
scrollProperties.setBorder(null);
splitPane.setBorder(null);
splitPane1.setBorder(null);
splitHolonElPro.setBorder(null);
panelHolonEl.setBorder(null);
canvasSP.setBorder(null);
holegJFrame.getContentPane().add(timePanel, BorderLayout.SOUTH);
// try {
// control.loadAutoSave(System.getProperty("user.home") + "/.config/HolonGUI/Category/Category.json");
// } catch (IOException e1) {
// }
canvasSP.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
GuiSettings.canvasSize.setX(Math.max(GuiSettings.canvasSize.getX(), canvasSP.getViewport().getWidth()));
GuiSettings.canvasSize
.setY(Math.max(GuiSettings.canvasSize.getY(), canvasSP.getViewport().getHeight()));
log.info("canvas.repaint11");
canvas.repaint();
}
});
}
private void tryToAlignObjects() {
//TODO(Tom2022-01-14): recreateTryToAlignObjects
}
private JFileChooser initSaveLoadFileChooser(){
JFileChooser safeLoadFileChooser = new JFileChooser(Preferences.userRoot().absolutePath());
safeLoadFileChooser.setFileFilter(new FileNameExtensionFilter("Holeg json files", "json"));
safeLoadFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
safeLoadFileChooser.setAcceptAllFileFilterUsed(false);
return safeLoadFileChooser;
}
private void initWindowMenu() {
menuBar.add(menuWindow);
// Algo
JMenuItem openMenu = new JMenuItem("Open Algorithm Panel", new ImageIcon(Import
.loadImage(ImagePreference.Button.Menu.Algo).getScaledInstance(20, 20, java.awt.Image.SCALE_SMOOTH)));
openMenu.addActionListener(actionEvent -> {
new AddOnWindow(holegJFrame, control);
});
openMenu.setAccelerator(KeyStroke.getKeyStroke('N', Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
menuWindow.add(openMenu);
// Outliner
JMenuItem openOutliner = new JMenuItem("Open Outliner", new ImageIcon(Import
.loadImage(ImagePreference.Button.Menu.Outliner).getScaledInstance(20, 20, java.awt.Image.SCALE_SMOOTH)));
openOutliner.addActionListener(actionEvent -> {
new Outliner(holegJFrame, model, control);
});
openOutliner
.setAccelerator(KeyStroke.getKeyStroke('O', Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
menuWindow.add(openOutliner);
// FlexWindow
JMenuItem openFlexMenuItem = new JMenuItem("Open Flexibility Panel", new ImageIcon(Import
.loadImage(ImagePreference.Button.Menu.Algo).getScaledInstance(20, 20, java.awt.Image.SCALE_SMOOTH)));
openFlexMenuItem.addActionListener(actionEvent -> {
new FlexWindow(holegJFrame, control);
});
openFlexMenuItem
.setAccelerator(KeyStroke.getKeyStroke('L', Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
menuWindow.add(openFlexMenuItem);
}
/**
* reloads the Categories from Model.
*
* @param categories the current categories
*/
private void updateCategories(Collection categories) {
DefaultTreeModel treemodel = new DefaultTreeModel(new DefaultMutableTreeNode("Categories") {
private static final long serialVersionUID = 1L;
{
DefaultMutableTreeNode node1;
for (Category c : categories) {
node1 = new DefaultMutableTreeNode(c.getName());
for (AbstractCanvasObject obj : c.getObjects()) {
node1.add(new DefaultMutableTreeNode(obj.getName()));
}
add(node1);
}
}
});
categoryTree.setModel(treemodel);
}
/**
* When changes are made to the Categories.
*
* @param categories the Categories
*/
public void updateCategoryUI(Collection categories) {
DefaultTreeModel model = (DefaultTreeModel) categoryTree.getModel();
updateCategories(categories);
model.reload();
}
void setVisible(boolean value) {
holegJFrame.setVisible(value);
}
/*
* Open a new Tab with an UpperNodeCanvas
*/
public void openNewUpperNodeTab(GroupNode node) {
chooseTabTemp();
JScrollPane scrollPane = getScrollPaneFromTabbedPane();
if (scrollPane.getViewport().getComponent(0)instanceof Canvas canvasPanel) {
unc = new Canvas(control, node);
}
// check if tab already open for clicked NodeOfNode
boolean dupl = false;
for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
JScrollPane paneOriginal = (JScrollPane) tabbedPaneInnerOriginal.getComponentAt(i);
if (paneOriginal != null && ((Canvas) paneOriginal.getViewport().getComponent(0)).getGroupNode()
.getId() == node.getId()) {
dupl = true;
// set selected component to view
tabbedPaneOriginal.setSelectedComponent(tabbedPaneInnerOriginal);
// set selected tab in view to found upper-node-canvas
tabbedPaneInnerOriginal.setSelectedComponent(tabbedPaneInnerOriginal.getComponentAt(i));
}
// if we found a duplicate, break
if (dupl) {
break;
}
}
if (!dupl) {
JScrollPane sp = new JScrollPane(unc);
sp.setBorder(null);
// Selected tabbed Pane = tabbedPaneOriginal or tabbedPaneSplit
if (tabTemp == tabbedPaneOriginal) {
this.tabbedPaneInnerOriginal.add(node.getName(), sp);
this.tabbedPaneInnerOriginal.setSelectedComponent(sp);
this.tabbedPaneInnerOriginal.setTabComponentAt(this.tabbedPaneInnerOriginal.getTabCount() - 1,
new ButtonTabComponent(this.tabbedPaneInnerOriginal));
}
}
}
/**
* Removes UpperNodeTab if UpperNode was deleted
*
* @param cps the CPS object that is currently selected
*/
private void removeUpperNodeTab(AbstractCanvasObject cps) {
if (cps instanceof GroupNode) {
for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
JScrollPane scrollPaneOriginal = (JScrollPane) tabbedPaneInnerOriginal.getComponentAt(i);
if (scrollPaneOriginal == null) {
} else if (((Canvas) scrollPaneOriginal.getViewport().getComponent(0)).getGroupNode()
.getId() == cps.getId()) {
((ButtonTabComponent) tabbedPaneInnerOriginal.getTabComponentAt(i)).removeTabs();
break;
}
}
}
}
/**
* chooses whether to set the tabTemp to tabbedPaneOriginal or tabbedPaneSplit
*/
private void chooseTabTemp() {
// TODO(Tom2021-12-1) Remove tabTabbed
tabTemp = tabbedPaneOriginal;
}
private JScrollPane getScrollPaneFromTabbedPane() {
return getScrollPaneFromTabbedPane(-1);
}
private JScrollPane getScrollPaneFromTabbedPane(int index) {
Component upperLevelSelectedComponent;
if (tabTemp == null) {
return null;
}
if (index == -1) {
upperLevelSelectedComponent = tabTemp.getSelectedComponent();
} else {
upperLevelSelectedComponent = tabTemp.getComponentAt(index);
}
if (upperLevelSelectedComponent instanceof JTabbedPane) {
Component nextLevel = ((JTabbedPane) upperLevelSelectedComponent).getSelectedComponent();
if (nextLevel instanceof JPanel panel)
return (JScrollPane) panel.getComponent(0);
else
return (JScrollPane) nextLevel;
} else if (upperLevelSelectedComponent instanceof JScrollPane scrollPane) {
return scrollPane;
} else {
return null;
}
}
private void openWebpage(String URL) {
try {
java.awt.Desktop.getDesktop().browse(new URI(URL));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* closes all UpperNodeTabs, that don't have a valid UpperNode (e.g. if it was
* ungrouped/deleted/replaced and so on)
*/
private void closeInvalidUpperNodeTabs() {
/**
* close bugged Tabs
*/
for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
JScrollPane scrollPaneOriginal = (JScrollPane) tabbedPaneInnerOriginal.getComponentAt(i);
if (((Canvas) scrollPaneOriginal.getViewport().getComponent(0)).getGroupNode() == null) {
((ButtonTabComponent) tabbedPaneInnerOriginal.getTabComponentAt(i)).removeTabs();
break;
}
}
}
public void repaintCanvas() {
log.info("repaintCanvas");
tabbedPaneInnerOriginal.revalidate();
tabbedPaneInnerOriginal.repaint();
for (int i = 1; i < tabbedPaneInnerOriginal.getTabCount(); i++) {
JScrollPane scrollPaneOriginal = (JScrollPane) tabbedPaneInnerOriginal.getComponentAt(i);
scrollPaneOriginal.revalidate();
}
}
}