HolonView.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. package ui.view.outliner;
  2. import java.awt.BorderLayout;
  3. import java.awt.Component;
  4. import java.awt.Dimension;
  5. import java.awt.datatransfer.DataFlavor;
  6. import java.awt.datatransfer.Transferable;
  7. import java.awt.datatransfer.UnsupportedFlavorException;
  8. import java.awt.event.MouseAdapter;
  9. import java.awt.event.MouseEvent;
  10. import java.io.IOException;
  11. import javax.swing.AbstractCellEditor;
  12. import javax.swing.DropMode;
  13. import javax.swing.Icon;
  14. import javax.swing.ImageIcon;
  15. import javax.swing.JCheckBoxMenuItem;
  16. import javax.swing.JComponent;
  17. import javax.swing.JLabel;
  18. import javax.swing.JMenuItem;
  19. import javax.swing.JPanel;
  20. import javax.swing.JPopupMenu;
  21. import javax.swing.JTextField;
  22. import javax.swing.JTree;
  23. import javax.swing.SwingUtilities;
  24. import javax.swing.ToolTipManager;
  25. import javax.swing.TransferHandler;
  26. import javax.swing.tree.DefaultMutableTreeNode;
  27. import javax.swing.tree.DefaultTreeCellRenderer;
  28. import javax.swing.tree.TreeCellEditor;
  29. import javax.swing.tree.TreePath;
  30. import javax.swing.tree.TreeSelectionModel;
  31. import classes.Holon;
  32. import classes.HolonElement;
  33. import classes.HolonObject;
  34. import ui.controller.Control;
  35. import utility.ImageImport;
  36. /**
  37. * An Outliner Tab.
  38. * A high level view on the Model with respect to the Holon Structure.
  39. * @author Tom
  40. *
  41. */
  42. public class HolonView extends JPanel{
  43. private Control control;
  44. private JTree holonTree;
  45. private DefaultMutableTreeNode root;
  46. private boolean showHolonElementsInTree = true;
  47. public HolonView(Outliner parent, Control control) {
  48. this.control = control;
  49. this.setLayout(new BorderLayout());
  50. initilizePanel();
  51. parent.outlinerUpdate.addListener(() -> updateTreeStructure());
  52. }
  53. private void initilizePanel() {
  54. holonTree = generateTree();
  55. holonTree.setCellRenderer(new HolonJtreeRenderer());
  56. holonTree.setDragEnabled(true);
  57. holonTree.setDropMode(DropMode.ON_OR_INSERT);
  58. holonTree.setTransferHandler(new HolonTransferHandler());
  59. holonTree.getSelectionModel().setSelectionMode(
  60. TreeSelectionModel.SINGLE_TREE_SELECTION);
  61. ToolTipManager.sharedInstance().registerComponent(holonTree);
  62. TreeUtils.expand(holonTree);
  63. holonTree.setRootVisible(true);
  64. holonTree.addMouseListener(new HolonMouseListener());
  65. holonTree.setEditable(true);
  66. holonTree.setCellEditor(new HolonNodeEditor());
  67. this.add(TreeUtils.makePanelFromTree(holonTree));
  68. }
  69. private JTree generateTree() {
  70. root = generateFromHolon(control.getModel().getStateHolon());
  71. return new JTree(root);
  72. }
  73. private DefaultMutableTreeNode generateFromHolon(Holon holon) {
  74. DefaultMutableTreeNode node = new DefaultMutableTreeNode(new HolonInfo(holon));
  75. for(Holon child : holon.getChildView()) {
  76. node.add(generateFromHolon(child));
  77. }
  78. if(this.showHolonElementsInTree) {
  79. for(HolonElement ele : holon.getElementView()) {
  80. node.add(new DefaultMutableTreeNode(new ElementInfo(ele)));
  81. }
  82. }
  83. return node;
  84. }
  85. private void updateTreeStructure() {
  86. holonTree.clearSelection();
  87. root.removeAllChildren();
  88. Holon holon = control.getModel().getStateHolon();
  89. for(Holon child : holon.getChildView()) {
  90. root.add(generateFromHolon(child));
  91. }
  92. if(this.showHolonElementsInTree) {
  93. for(HolonElement ele : holon.getElementView()) {
  94. root.add(new DefaultMutableTreeNode(new ElementInfo(ele)));
  95. }
  96. }
  97. holonTree.updateUI();
  98. TreeUtils.expand(holonTree);
  99. }
  100. interface HolonNode{
  101. public Transferable getTransferable(HolonTransferHandler handler);
  102. public Icon getIcon();
  103. public String getToolTip();
  104. public void SetName(String name);
  105. }
  106. static final Icon elementIcon = new ImageIcon(ImageImport.loadImage("/Button_Images/element.png",16,16));
  107. static final String elementToolTip = "Element";
  108. class ElementInfo implements HolonNode{
  109. private HolonElement element;
  110. ElementInfo(HolonElement element){
  111. this.element = element;
  112. }
  113. @Override
  114. public String toString(){
  115. return element.getName();
  116. }
  117. public HolonElement getElement()
  118. {
  119. return element;
  120. }
  121. @Override
  122. public Transferable getTransferable(HolonTransferHandler handler) {
  123. return handler.new ElementTransferable(element);
  124. }
  125. @Override
  126. public Icon getIcon() {
  127. return elementIcon;
  128. }
  129. @Override
  130. public String getToolTip() {
  131. return elementToolTip;
  132. }
  133. @Override
  134. public void SetName(String name) {
  135. element.setEleName(name);
  136. }
  137. }
  138. static final Icon holonIcon = new ImageIcon(ImageImport.loadImage("/Button_Images/holon_logic.png",16,16));
  139. static final Icon holonPhysicalIcon = new ImageIcon(ImageImport.loadImage("/Button_Images/holon_physical.png",16,16));
  140. static final String holonToolTip = "Holon";
  141. class HolonInfo implements HolonNode{
  142. private Holon holon;
  143. HolonInfo(Holon holon){
  144. this.holon = holon;
  145. }
  146. @Override
  147. public String toString(){
  148. return holon.name;
  149. }
  150. public Holon getElement()
  151. {
  152. return holon;
  153. }
  154. public void AddElement(HolonElement element) {
  155. if(element.holon != null) {
  156. element.holon.removeElement(element);
  157. }
  158. holon.addElement(element);
  159. }
  160. public void AddHolon(Holon holon) {
  161. holon.removeFromParent();
  162. this.holon.addChild(holon);
  163. }
  164. @Override
  165. public Transferable getTransferable(HolonTransferHandler handler) {
  166. return handler.new HolonTransferable(holon);
  167. }
  168. @Override
  169. public Icon getIcon() {
  170. return holon.isPhysical? holonPhysicalIcon: holonIcon;
  171. }
  172. @Override
  173. public String getToolTip() {
  174. return holonToolTip;
  175. }
  176. @Override
  177. public void SetName(String name) {
  178. holon.name = name;
  179. }
  180. }
  181. //Context Menu
  182. class HolonMouseListener extends MouseAdapter{
  183. JPopupMenu menu = new JPopupMenu ();
  184. JCheckBoxMenuItem showElements = new JCheckBoxMenuItem("Show Elements");
  185. JMenuItem newHolonAsParentItem = new JMenuItem("Create new Holon as Parent");
  186. JMenuItem newHolonAsChildItem = new JMenuItem("Create new Holon as Child");
  187. JMenuItem deleteThisHolon = new JMenuItem("Delete this Holon");
  188. public HolonMouseListener() {
  189. //Initialize MenuItems
  190. showElements.setState(showHolonElementsInTree);
  191. showElements.addActionListener(clicked -> {
  192. showHolonElementsInTree = showElements.getState();
  193. updateTreeStructure();
  194. });
  195. newHolonAsParentItem.addActionListener(clicked -> {
  196. TreePath path = holonTree.getSelectionPath();
  197. HolonInfo info = getInfoFromPath(path);
  198. if(info == null) return;
  199. Holon parent = info.holon.getParent();
  200. parent.removeChildHolon(info.holon);
  201. Holon newHolon = new Holon("New Holon");
  202. newHolon.addChild(info.holon);
  203. parent.addChild(newHolon);
  204. updateTreeStructure();
  205. });
  206. newHolonAsChildItem.addActionListener(clicked -> {
  207. TreePath path = holonTree.getSelectionPath();
  208. HolonInfo info = getInfoFromPath(path);
  209. if(info == null) return;
  210. info.holon.addChild(new Holon("New Holon"));
  211. updateTreeStructure();
  212. });
  213. deleteThisHolon.addActionListener(clicked -> {
  214. TreePath path = holonTree.getSelectionPath();
  215. HolonInfo info = getInfoFromPath(path);
  216. if(info == null) return;
  217. HolonObject obj = info.holon.getHolonObject();
  218. if(obj != null) {
  219. info.holon.reassignAllChildren(info.holon.getParent());
  220. }else {
  221. info.holon.reassignAllChildren(info.holon.getParent());
  222. info.holon.removeFromParent();
  223. info.holon.removeAllRefrences();
  224. }
  225. updateTreeStructure();
  226. });
  227. //CreateMenu
  228. menu.add(showElements);
  229. menu.addSeparator();
  230. menu.add(newHolonAsParentItem);
  231. menu.add(newHolonAsChildItem);
  232. menu.add(deleteThisHolon);
  233. }
  234. public void mousePressed ( MouseEvent e )
  235. {
  236. if (!SwingUtilities.isRightMouseButton(e))
  237. {
  238. return;
  239. }
  240. TreePath path = holonTree.getSelectionPath();
  241. boolean pathIsViable = (path != null);
  242. newHolonAsParentItem.setVisible(pathIsViable);
  243. newHolonAsChildItem.setVisible(pathIsViable);
  244. deleteThisHolon.setVisible(pathIsViable);
  245. menu.show(holonTree, e.getX(), e.getY());
  246. }
  247. HolonInfo getInfoFromPath(TreePath path) {
  248. if(path == null) {
  249. return null;
  250. }
  251. DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
  252. if(!(node.getUserObject() instanceof HolonInfo)) {
  253. return null;
  254. }
  255. return (HolonInfo)node.getUserObject();
  256. }
  257. }
  258. //Drag and Drop
  259. //Make drag and drop von Holons possible.
  260. //Implement HolonElement drag and drop too, but its disabled.
  261. class HolonTransferHandler extends TransferHandler{
  262. DataFlavor holonFlavor;
  263. DataFlavor[] holonFlavorArray = new DataFlavor[1];
  264. DataFlavor elementFlavor;
  265. DataFlavor[] elementFlavorArray = new DataFlavor[1];
  266. boolean allowHolonElementDragAndDrop = false;
  267. HolonTransferHandler(){
  268. try {
  269. String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
  270. ";class=\"" +
  271. classes.Holon.class.getName() +
  272. "\"";
  273. holonFlavor = new DataFlavor(mimeType);
  274. holonFlavorArray[0] = holonFlavor;
  275. mimeType = DataFlavor.javaJVMLocalObjectMimeType +
  276. ";class=\"" +
  277. classes.HolonElement.class.getName() +
  278. "\"";
  279. elementFlavor = new DataFlavor(mimeType);
  280. elementFlavorArray[0] = elementFlavor;
  281. } catch (ClassNotFoundException e) {
  282. e.printStackTrace();
  283. }
  284. }
  285. @Override
  286. public boolean canImport(TransferHandler.TransferSupport support) {
  287. if(!support.isDrop()) {
  288. return false;
  289. }
  290. support.setShowDropLocation(true);
  291. //Only accept Element and Holon as Drop
  292. if(!support.isDataFlavorSupported(holonFlavor) && !support.isDataFlavorSupported(elementFlavor)) {
  293. return false;
  294. }
  295. JTree.DropLocation location = (JTree.DropLocation)support.getDropLocation();
  296. TreePath pathDrop = location.getPath();
  297. DefaultMutableTreeNode node = (DefaultMutableTreeNode) pathDrop.getLastPathComponent();
  298. //Element cannot be parent of a holon
  299. if(!(node.getUserObject() instanceof HolonInfo)) {
  300. return false;
  301. }
  302. JTree tree = (JTree) support.getComponent();
  303. TreePath pathDrag = tree.getSelectionPath();
  304. //Dont allow Cycles
  305. if(pathDrag.isDescendant(pathDrop)) {
  306. return false;
  307. }
  308. //Check physical connected
  309. try {
  310. Holon dropHolon = ((HolonInfo) node.getUserObject()).holon;
  311. Holon dragHolon = (Holon) support.getTransferable().getTransferData(holonFlavor);
  312. boolean physicalConnected = dropHolon.checkHolonArePhysicalConnected(dragHolon, control);
  313. boolean isAllStateHolon = dropHolon.getLayer() == 0;
  314. return physicalConnected || isAllStateHolon;
  315. } catch (UnsupportedFlavorException | IOException e) {
  316. e.printStackTrace();
  317. return false;
  318. }
  319. }
  320. @Override
  321. public boolean importData(TransferHandler.TransferSupport support) {
  322. if(!canImport(support)) {
  323. return false;
  324. }
  325. JTree.DropLocation location = (JTree.DropLocation)support.getDropLocation();
  326. TreePath path = location.getPath();
  327. DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
  328. if(node.getUserObject() instanceof HolonInfo) {
  329. HolonInfo info = (HolonInfo) node.getUserObject();
  330. try {
  331. if(support.isDataFlavorSupported(holonFlavor)) {
  332. info.AddHolon((Holon) support.getTransferable().getTransferData(holonFlavor));
  333. }else if (support.isDataFlavorSupported(elementFlavor)){
  334. info.AddElement((HolonElement) support.getTransferable().getTransferData(elementFlavor));
  335. }
  336. } catch (UnsupportedFlavorException | IOException e) {
  337. e.printStackTrace();
  338. }
  339. }
  340. return false;
  341. }
  342. protected void exportDone(JComponent source,
  343. Transferable data,
  344. int action) {
  345. updateTreeStructure();
  346. }
  347. @Override
  348. public int getSourceActions(JComponent c) {
  349. return MOVE;
  350. }
  351. @Override
  352. protected Transferable createTransferable(JComponent c) {
  353. JTree tree = (JTree)c;
  354. TreePath path = tree.getSelectionPath();
  355. if(path != null) {
  356. DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
  357. Object userObject = node.getUserObject();
  358. //Only allow Hollon to move
  359. if(this.allowHolonElementDragAndDrop) {
  360. //Both
  361. if(userObject instanceof HolonNode) {
  362. return ((HolonNode) userObject).getTransferable(this);
  363. }
  364. }
  365. else {
  366. //Only Holons
  367. if(userObject instanceof HolonInfo) {
  368. return ((HolonInfo) userObject).getTransferable(this);
  369. }
  370. }
  371. }
  372. return null;
  373. }
  374. public class HolonTransferable implements Transferable{
  375. Holon holon;
  376. public HolonTransferable(Holon holon) {
  377. this.holon = holon;
  378. }
  379. @Override
  380. public DataFlavor[] getTransferDataFlavors() {
  381. return holonFlavorArray;
  382. }
  383. @Override
  384. public boolean isDataFlavorSupported(DataFlavor flavor) {
  385. return holonFlavor.equals(flavor);
  386. }
  387. @Override
  388. public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
  389. if(!isDataFlavorSupported(flavor))
  390. throw new UnsupportedFlavorException(flavor);
  391. return holon;
  392. }
  393. }
  394. public class ElementTransferable implements Transferable{
  395. HolonElement element;
  396. public ElementTransferable(HolonElement element) {
  397. this.element = element;
  398. }
  399. @Override
  400. public DataFlavor[] getTransferDataFlavors() {
  401. return elementFlavorArray;
  402. }
  403. @Override
  404. public boolean isDataFlavorSupported(DataFlavor flavor) {
  405. return elementFlavor.equals(flavor);
  406. }
  407. @Override
  408. public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
  409. if(!isDataFlavorSupported(flavor))
  410. throw new UnsupportedFlavorException(flavor);
  411. return element;
  412. }
  413. }
  414. }
  415. //Cell Display
  416. class HolonJtreeRenderer extends DefaultTreeCellRenderer {
  417. public Component getTreeCellRendererComponent(
  418. JTree tree,
  419. Object value,
  420. boolean isSelected,
  421. boolean expanded,
  422. boolean leaf,
  423. int row,
  424. boolean hasFocus) {
  425. super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, hasFocus);
  426. DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
  427. HolonNode Node = (HolonNode) node.getUserObject();
  428. if(row != 0) {
  429. this.setIcon(Node.getIcon());
  430. this.setToolTipText(Node.getToolTip());
  431. }
  432. return this;
  433. }
  434. }
  435. //Edit Names of Nodes
  436. class HolonNodeEditor extends AbstractCellEditor implements TreeCellEditor{
  437. private HolonNode holonNode;
  438. private JTextField tf= new JTextField(){
  439. @Override
  440. public Dimension getPreferredSize() {
  441. Dimension dim = super.getPreferredSize();
  442. int length = getText().length();
  443. dim.width = Math.max(300, dim.width + length * 10) ;
  444. return dim;
  445. }
  446. };
  447. public HolonNodeEditor() {
  448. super();
  449. }
  450. @Override
  451. public Object getCellEditorValue() {
  452. holonNode.SetName(tf.getText());
  453. return tf.getText();
  454. }
  455. @Override
  456. public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded,
  457. boolean leaf, int row) {
  458. JLabel newString = (JLabel) holonTree.getCellRenderer().getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, leaf);
  459. DefaultMutableTreeNode default_node = (DefaultMutableTreeNode) value;
  460. holonNode = (HolonNode)default_node.getUserObject();
  461. tf.setText(newString.getText());
  462. return tf;
  463. }
  464. }
  465. }