VisualizationInteractor.java 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. package de.tu_darmstadt.tk.SmartHomeNetworkSim.view;
  2. import java.awt.Point;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. import java.awt.event.KeyEvent;
  6. import java.awt.event.KeyListener;
  7. import java.awt.event.MouseEvent;
  8. import java.awt.event.MouseMotionListener;
  9. import java.awt.geom.Line2D;
  10. import java.util.LinkedList;
  11. import javax.swing.JMenu;
  12. import javax.swing.JMenuItem;
  13. import javax.swing.JPopupMenu;
  14. import javax.swing.SwingUtilities;
  15. import javax.swing.event.MouseInputListener;
  16. import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.SettingsController;
  17. import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
  18. import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.NetworkController;
  19. import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.PacketCaptureController;
  20. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Connection;
  21. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.ConnectionPerformance;
  22. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
  23. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Packet;
  24. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.PacketCollector;
  25. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;
  26. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
  27. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.configuration.SelectionModel;
  28. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation.SimpleLink;
  29. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation.SimpleProtocol;
  30. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.Pair;
  31. import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.popups.ConnectionCreationDialog;
  32. import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.popups.EditPacketSniffer;
  33. import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.popups.LinkCreationDialog;
  34. import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.popups.SmartDeviceCreationPopUp;
  35. import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.util.LinkToolTip;
  36. import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.util.Utility;
  37. /**
  38. * Listener which detects User Interaction with the {@link VisualizationPanel},
  39. * stores interaction information, triggers the controller and helps
  40. * visualization of the interaction
  41. *
  42. * @author Andreas T. Meyer-Berg
  43. */
  44. public class VisualizationInteractor implements MouseInputListener,
  45. MouseMotionListener, ActionListener, KeyListener {
  46. /**
  47. * Controller to notify when the model changes
  48. */
  49. private Controller controller;
  50. /**
  51. * Configurations
  52. */
  53. private SettingsController config;
  54. /**
  55. * Network Controller
  56. */
  57. private NetworkController network;
  58. /**
  59. * Panel which is observed
  60. */
  61. private VisualizationPanel panel;
  62. /**
  63. * Menu which is shown on right clicks
  64. */
  65. private JPopupMenu rightClickMenu;
  66. /**
  67. * RightClick MenuItem for SmartDevice creation
  68. */
  69. private JMenuItem itemCreate;
  70. /**
  71. * RightClick MenuItem for Link creation
  72. */
  73. private JMenuItem itemCreateLink;
  74. /**
  75. * RightClick MenuItem for Connection creation
  76. */
  77. private JMenuItem itemCreateConnection;
  78. /**
  79. * RightClickMenu for editing connections
  80. */
  81. private JMenu itemEditConnection;
  82. /**
  83. * RightClickMenu for options for capturing of packets
  84. */
  85. private JMenu itemCapture;
  86. /**
  87. * Position of editCreate connection in the Rightclick menu
  88. */
  89. private int editCreateConnectionIndex = 2;
  90. /**
  91. * RightClick MenuItem for SmartDevice deletion
  92. */
  93. private JMenuItem itemDelete;
  94. /**
  95. * RightClick MenuItem for deletion of multiple selected SmartDevices
  96. */
  97. private JMenuItem itemDeleteSelected;
  98. /**
  99. * RightClick MenuItem for debug purposes
  100. */
  101. private JMenuItem itemDebug;
  102. /**
  103. * SmartDevice that is dragged on Screen
  104. */
  105. public SmartDevice dragged = null;
  106. /**
  107. * Current x Position of the dragged device
  108. */
  109. public int dragged_x;
  110. /**
  111. * Current y Position of the dragged device
  112. */
  113. public int dragged_y;
  114. /**
  115. * x Position where the drage begun
  116. */
  117. public int dragged_x_start;
  118. /**
  119. * y Position where the drag begun
  120. */
  121. public int dragged_y_start;
  122. /**
  123. * true if an selected device was dragged
  124. */
  125. private boolean draggedDeviceWasSelected = false;
  126. /**
  127. * No interaction
  128. */
  129. public static final byte NOTHING = 0;
  130. /**
  131. * Right-click menu is shown
  132. */
  133. public static final byte RIGHTCLICK_MENU = 1;
  134. /**
  135. * Drag of multiple selected devices
  136. */
  137. public static final byte SELECTED_DRAG = 2;
  138. /**
  139. * drag to create connection
  140. */
  141. public static final byte DRAG_CONNECTION = 3;
  142. /**
  143. * Drag to select multiple devices
  144. */
  145. public static final byte DRAG_SELECT = 4;
  146. /**
  147. * Devices are selected on the screen
  148. */
  149. public static final byte SELECTED = 5;
  150. /**
  151. * Mode, which action is currently executed
  152. */
  153. public byte mode = NOTHING;
  154. /**
  155. * SmartDevice that was clicked
  156. */
  157. private SmartDevice clicked = null;
  158. /**
  159. * Device where the current connection is dragged from
  160. */
  161. public SmartDevice connectionFrom = null;
  162. /**
  163. * True if the ControlKey is currently pressed
  164. */
  165. public boolean controlDown = false;
  166. /**
  167. * ToolTip which describes the Links
  168. */
  169. private LinkToolTip toolTip;
  170. /**
  171. * Link which was clicked
  172. */
  173. private Link clickedLink = null;
  174. /**
  175. * PacketCapture Controller, for capturing packets
  176. */
  177. private PacketCaptureController captureController;
  178. SelectionModel selectionModel;
  179. /**
  180. * Creates a new VisualisationInteractor
  181. *
  182. * @param controller
  183. * controller that is accessed
  184. * @param panel
  185. * which should visualize the interactions
  186. */
  187. public VisualizationInteractor(Controller controller,
  188. VisualizationPanel panel) {
  189. // Initialize the values
  190. this.controller = controller;
  191. this.panel = panel;
  192. this.config = controller.getSettingsController();
  193. this.network = controller.getNetworkController();
  194. this.toolTip = new LinkToolTip();
  195. this.captureController = controller.getSimulationController().getPacketCaptureController();
  196. this.selectionModel = controller.getSettingsController().getConfigurationManager().getSelectionModel();
  197. initializeRightClickMenu();
  198. }
  199. @Override
  200. public void mouseClicked(MouseEvent e) {
  201. toolTip.setEnabled(false);
  202. /*
  203. * FindSmartDevice that was clicked
  204. */
  205. clicked = getSmartDeviceAtPosition(e.getX(), e.getY());
  206. selectionModel.clickedConnection.clear();
  207. if(clicked == null)
  208. selectionModel.clickedConnection = getConnectionsAtPosition(e.getX(), e.getY());
  209. switch (mode) {
  210. case DRAG_CONNECTION:
  211. finishConnectionCreation();
  212. break;
  213. case SELECTED_DRAG:
  214. // Finish Drag Device operations
  215. finishDrag();
  216. case SELECTED:
  217. case NOTHING:
  218. // If Rightclick
  219. if (SwingUtilities.isRightMouseButton(e)) {
  220. // Show the RightClickMenu
  221. Link linkAtPosition = getLinkVisualizationAtPosition(e.getX(), e.getY());
  222. showRightClickMenu(clicked, linkAtPosition);
  223. break;
  224. }
  225. if(!selectionModel.selectedDevices.isEmpty()&&!controlDown){
  226. selectionModel.selectedDevices.clear();
  227. if (clicked == null) {
  228. panel.repaint();
  229. }
  230. }
  231. if(clicked!=null){
  232. if(!controlDown)
  233. selectionModel.selectedDevices.add(clicked);
  234. else if(selectionModel.selectedDevices.remove(clicked)&&!draggedDeviceWasSelected){
  235. selectionModel.selectedDevices.add(clicked);
  236. }
  237. mode = SELECTED;
  238. panel.repaint();
  239. }else{
  240. if(!controlDown)
  241. mode = NOTHING;
  242. else if(!selectionModel.selectedDevices.isEmpty())
  243. mode = SELECTED;
  244. panel.repaint();
  245. }
  246. break;
  247. default:
  248. break;
  249. }
  250. }
  251. @Override
  252. public void mousePressed(MouseEvent e) {
  253. toolTip.setEnabled(false);
  254. // Save mouse position for right Click options
  255. dragged_x = e.getX();
  256. dragged_y = e.getY();
  257. // Check if SmartDevice was clicked
  258. SmartDevice pressedOn = getSmartDeviceAtPosition(dragged_x, dragged_y);
  259. switch (mode) {
  260. case SELECTED:
  261. if(!controlDown)
  262. mode = NOTHING;
  263. case RIGHTCLICK_MENU:
  264. case NOTHING:
  265. if (pressedOn == null){
  266. //Click drag - multi select
  267. dragged_x_start = e.getX();
  268. dragged_y_start = e.getY();
  269. mode = DRAG_SELECT;
  270. if(!controlDown && !SwingUtilities.isRightMouseButton(e))
  271. selectionModel.selectedDevices.clear();
  272. break;
  273. } else if (e.getButton() == MouseEvent.BUTTON1){// && connectionFrom == null) {
  274. // Recognize possible drag operation
  275. draggedDeviceWasSelected = selectionModel.selectedDevices.contains(pressedOn);
  276. if(!draggedDeviceWasSelected){
  277. if(!controlDown)
  278. selectionModel.selectedDevices.clear();
  279. selectionModel.selectedDevices.add(pressedOn);
  280. }
  281. dragged = pressedOn;
  282. dragged_x = pressedOn.getX();
  283. dragged_y = pressedOn.getY();
  284. mode = SELECTED_DRAG;
  285. } else if (SwingUtilities.isRightMouseButton(e)){// && dragged == null) {
  286. connectionFrom = pressedOn;
  287. mode = DRAG_CONNECTION;
  288. }
  289. break;
  290. case DRAG_SELECT:
  291. finishDragSelect();
  292. break;
  293. default:
  294. mode = NOTHING;
  295. break;
  296. }
  297. panel.repaint();
  298. }
  299. @Override
  300. public void mouseReleased(MouseEvent e) {
  301. // Finish operation
  302. switch (mode) {
  303. case DRAG_SELECT:
  304. finishDragSelect();
  305. panel.repaint();
  306. break;
  307. case SELECTED_DRAG:
  308. finishDrag();
  309. break;
  310. case DRAG_CONNECTION:
  311. finishConnectionCreation();
  312. break;
  313. default:
  314. break;
  315. }
  316. }
  317. @Override
  318. public void mouseDragged(MouseEvent e) {
  319. toolTip.setEnabled(false);
  320. // move dragged object/object selection on screen
  321. switch (mode) {
  322. case DRAG_SELECT:
  323. case DRAG_CONNECTION:
  324. //Update position
  325. if (e.getX() < 0)
  326. dragged_x = 0;
  327. else if (e.getX() >= config.getWidth())
  328. dragged_x = config.getWidth()-1;
  329. else
  330. dragged_x = e.getX();
  331. if (e.getY() < 0)
  332. dragged_y = 0;
  333. else if (e.getY() >= config.getHeight())
  334. dragged_y = config.getHeight()-1;
  335. else
  336. dragged_y = e.getY();
  337. if(mode == DRAG_CONNECTION)
  338. break;
  339. //Update Selected objects, if DragSelect mode is active
  340. int min_x = Math.min(dragged_x, dragged_x_start);
  341. int min_y = Math.min(dragged_y, dragged_y_start);
  342. int max_x = Math.max(dragged_x, dragged_x_start);
  343. int max_y = Math.max(dragged_y, dragged_y_start);
  344. //Remove unselected
  345. selectionModel.selectedDevicesDrag.removeIf(s->(s.getX()<min_x||s.getX()>max_x||s.getY()<min_y||s.getY()>max_y));
  346. //Add selected devices
  347. for(SmartDevice sel:network.getVisibleSmartDevices()){
  348. if(sel.getX()>=min_x&&sel.getX()<=max_x&&sel.getY()>=min_y&&sel.getY()<=max_y&&!selectionModel.selectedDevicesDrag.contains(sel)){
  349. selectionModel.selectedDevicesDrag.add(sel);
  350. }
  351. }
  352. break;
  353. case SELECTED_DRAG:
  354. //new Position of the dragged Device
  355. dragged_x = e.getX();
  356. dragged_y = e.getY();
  357. //offset of the new Position - old position
  358. int x_offset = dragged_x - dragged.getX();
  359. int y_offset = dragged_y - dragged.getY();
  360. //Validate for all moved devices, that they are within the model, if not change offset
  361. for(SmartDevice d:selectionModel.selectedDevices){
  362. if (d.getX() + x_offset <= config.getDeviceVisualizationRadius())
  363. x_offset = config.getDeviceVisualizationRadius()-d.getX();
  364. else if (d.getX() + x_offset >= config.getWidth() - config.getDeviceVisualizationRadius())
  365. x_offset = config.getWidth() - config.getDeviceVisualizationRadius()-d.getX();
  366. if (d.getY() + y_offset <= config.getDeviceVisualizationRadius())
  367. y_offset = config.getDeviceVisualizationRadius()-d.getY();
  368. else if (d.getY() + y_offset >= config.getHeight() - config.getDeviceVisualizationRadius())
  369. y_offset = config.getHeight() - config.getDeviceVisualizationRadius()-d.getY();
  370. }
  371. //update the dragged position, if the offset changed
  372. dragged_x =dragged.getX() + x_offset;
  373. dragged_y =dragged.getY() + y_offset;
  374. break;
  375. default:
  376. break;
  377. }
  378. // repaint the dragged smartDevice or new connection
  379. if (mode == SELECTED_DRAG || mode == DRAG_CONNECTION || mode == DRAG_SELECT)
  380. panel.repaint();
  381. }
  382. /**
  383. * Finishes the drag operation, if a SmartDevice was dragged, repaint the
  384. * panel and set dragged to null
  385. */
  386. public void finishDrag() {
  387. if (mode == SELECTED_DRAG){
  388. if(dragged != null
  389. && (dragged.getX() != dragged_x || dragged.getY() != dragged_y)) {
  390. int x_offset = dragged_x-dragged.getX();
  391. int y_offset = dragged_y-dragged.getY();
  392. for(SmartDevice d: selectionModel.selectedDevices)
  393. network.moveSmartDevice(d, d.getX()+x_offset, d.getY()+y_offset, d.getZ());
  394. }
  395. dragged = null;
  396. if(selectionModel.selectedDevices.isEmpty())
  397. mode = NOTHING;
  398. else
  399. mode = SELECTED;
  400. panel.repaint();
  401. controller.notifyObservers();
  402. }
  403. }
  404. private void finishDragSelect() {
  405. LinkedList<SmartDevice> merged = new LinkedList<SmartDevice>();
  406. //XOR of controller.getControllerConfiguration().getConfigurationManager().getSelectionModel().selectedDevices and controller.getControllerConfiguration().getConfigurationManager().getSelectionModel().selectedDevices Drag
  407. merged.addAll(selectionModel.selectedDevices);
  408. merged.removeAll(selectionModel.selectedDevicesDrag);
  409. selectionModel.selectedDevicesDrag.removeAll(selectionModel.selectedDevices);
  410. merged.addAll(selectionModel.selectedDevicesDrag);
  411. //clear sets
  412. selectionModel.selectedDevices.clear();
  413. selectionModel.selectedDevicesDrag.clear();
  414. selectionModel.selectedDevices = merged;
  415. if(selectionModel.selectedDevices.isEmpty())
  416. mode = NOTHING;
  417. else
  418. mode = SELECTED;
  419. }
  420. /**
  421. * Finishes the create connection operation and open a PopUp for
  422. * Link/Connection creation
  423. */
  424. private void finishConnectionCreation() {
  425. /**
  426. * SmartDevice the connection was
  427. */
  428. SmartDevice connectionTo = getSmartDeviceAtPosition(dragged_x,
  429. dragged_y);
  430. if (mode == DRAG_CONNECTION && connectionFrom != null && connectionTo != null
  431. && connectionFrom != connectionTo) {
  432. // Create new Connection
  433. /**
  434. * Link of the new Connection
  435. */
  436. Link l = null;
  437. /**
  438. * Devices of the connection -> to find common Link
  439. */
  440. LinkedList<SmartDevice> devices = new LinkedList<SmartDevice>();
  441. devices.add(connectionFrom);
  442. devices.add(connectionTo);
  443. for(Link link:network.getLinks()){
  444. if(link.getDevices().containsAll(devices)){
  445. l = link;
  446. break;
  447. }
  448. }
  449. /**
  450. * Create new Connection if no link was found
  451. */
  452. if(l==null){
  453. l= new SimpleLink("Ethernet: " + connectionFrom.getName()
  454. + " to " + connectionTo.getName());
  455. l.addDevice(connectionFrom);
  456. l.addDevice(connectionTo);
  457. }
  458. //Create ports and add to controller
  459. Port p1 = new Port(connectionFrom, (short) 1,(long) (Math.random()*300+300));
  460. Port p2 = new Port(connectionTo, (short) 2,(long) (Math.random()*300+300));
  461. Connection c = new ConnectionPerformance(l, new SimpleProtocol(p1, p2));
  462. c.addSmartDevice(p1);
  463. c.addSmartDevice(p2);
  464. p1.setConnection(c);
  465. p2.setConnection(c);
  466. connectionTo.addLink(l);
  467. connectionTo.addPort(p2);
  468. connectionFrom.addLink(l);
  469. connectionFrom.addPort(p1);
  470. network.addConnectionToLink(c, l);
  471. network.addConnection(c);
  472. if(!network.getLinks().contains(l))
  473. network.addLink(l);
  474. }
  475. connectionFrom = null;
  476. if(selectionModel.selectedDevices.isEmpty())
  477. mode = NOTHING;
  478. else
  479. mode = SELECTED;
  480. panel.repaint();
  481. controller.notifyObservers();
  482. }
  483. /**
  484. * Returns SmartDevice which is at position (x,y) or within its
  485. * visualization radius. Returns null, if no SmartDevice is within the
  486. * range.
  487. *
  488. * @param x
  489. * x-position which should be checked
  490. * @param y
  491. * y-position which should be checked
  492. * @return {@link SmartDevice} at position (x,y) or null if there is no
  493. */
  494. private SmartDevice getSmartDeviceAtPosition(int x, int y) {
  495. // Check is device is inside visualization radius
  496. for (SmartDevice d : network.getVisibleSmartDevices()) {
  497. if (Math.abs(d.getX() - x) < config.getDeviceVisualizationRadius()
  498. && Math.abs(d.getY() - y) < config.getDeviceVisualizationRadius()) {
  499. /**
  500. * correct distance / radius from the smartDevice
  501. */
  502. int radius = (int) Math.floor(Math.sqrt((d.getX() - x)*(d.getX() - x)+(d.getY() - y)*(d.getY() - y)));
  503. if(radius <= config.getDeviceVisualizationRadius())
  504. return d;
  505. }
  506. }
  507. return null;
  508. }
  509. /**
  510. * Returns all Connections, which cross point (x,y)
  511. * @param x xPosition of the point (x,y)
  512. * @param y yPosition of the point (x,y)
  513. * @return List of all possible clicked Connections
  514. */
  515. private LinkedList<Pair<Connection, Pair<Port, Port>>> getConnectionsAtPosition(int x, int y) {
  516. LinkedList<Pair<Connection,Pair<Port,Port>>> edges = new LinkedList<Pair<Connection,Pair<Port,Port>>>();
  517. // Check is device is inside visualization radius
  518. for(Connection c: network.getVisibleConnections()){
  519. if(c.getProtocol()==null)
  520. continue;
  521. for(Pair<Port, Port> p: c.getProtocol().getTopology()){
  522. if(pointOnConnection(x,y,p)){
  523. edges.add(new Pair<Connection, Pair<Port,Port>>(c, p));
  524. //break;//Connection was clicked - check for further connections
  525. }
  526. }
  527. }
  528. return edges;
  529. }
  530. /**
  531. * Returns true if the point (x,y) is on the connection part p.
  532. *
  533. * @param x xPosition of the Point
  534. * @param y yPosition of the Point
  535. * @param p connection part, which connects to Ports with a line
  536. * @return true if point is on connection, else false
  537. */
  538. private boolean pointOnConnection(int x, int y, Pair<Port, Port> p) {
  539. /** Filter invalid lines to prevent nullpointers */
  540. if(p==null||p.getLeft()==null||p.getRight()==null||p.getLeft().getOwner()==null
  541. ||p.getRight().getOwner()==null)
  542. return false;
  543. /** Number of pixels between click and connection, which should be recognized as click on the connection */
  544. double hitBoxThreshold = 4;
  545. /** Connection which might be clicked */
  546. Line2D con = new Line2D.Float(p.getLeft().getOwner().getX(), p.getLeft().getOwner().getY(), p.getRight().getOwner().getX(), p.getRight().getOwner().getY());
  547. /** Distance between click and connection */
  548. double dist = con.ptSegDist(x, y);
  549. /** Return true if within threshold */
  550. return dist<hitBoxThreshold;
  551. }
  552. @Override
  553. public void keyTyped(KeyEvent e) {
  554. if(e.getKeyCode()==KeyEvent.VK_CONTROL){
  555. if(controlDown!=true){
  556. controlDown = true;
  557. panel.repaint();
  558. }
  559. }
  560. if(e.getKeyCode()==KeyEvent.VK_A && controlDown){
  561. selectAllDevics();
  562. }
  563. if(e.getKeyCode()==KeyEvent.VK_ESCAPE){
  564. deselectAllDevics();
  565. }
  566. }
  567. /**
  568. * Select all Devices
  569. */
  570. private void selectAllDevics(){
  571. deselectAllDevics();
  572. config.getConfigurationManager().getSelectionModel().selectedDevices.addAll(controller.getNetworkController().getVisibleSmartDevices());
  573. panel.repaint();
  574. }
  575. /**
  576. * Deselect all Devices
  577. */
  578. private void deselectAllDevics(){
  579. config.getConfigurationManager().getSelectionModel().selectedDevicesDrag.clear();
  580. config.getConfigurationManager().getSelectionModel().selectedDevices.clear();
  581. panel.repaint();
  582. }
  583. @Override
  584. public void keyPressed(KeyEvent e) {
  585. if(e.getKeyCode()==KeyEvent.VK_CONTROL){
  586. if(controlDown!=true){
  587. controlDown = true;
  588. panel.repaint();
  589. }
  590. }
  591. if(e.getKeyCode()==KeyEvent.VK_A && controlDown){
  592. selectAllDevics();
  593. }
  594. if(e.getKeyCode()==KeyEvent.VK_ESCAPE){
  595. deselectAllDevics();
  596. }
  597. if(e.getKeyCode()==KeyEvent.VK_F2){
  598. /** mouse position */
  599. Point p = panel.getMousePosition();
  600. if(p!=null){
  601. /** Device at mouse */
  602. SmartDevice d = getSmartDeviceAtPosition((int)p.getX(), (int)p.getY());
  603. if(d!=null){
  604. /**
  605. * PopUp for editing the given device
  606. */
  607. SmartDeviceCreationPopUp popUp = new SmartDeviceCreationPopUp(d, true,controller);
  608. popUp.setLocationRelativeTo(panel);
  609. popUp.setEnabled(true);
  610. popUp.setVisible(true);
  611. popUp.setNameFocus();
  612. }
  613. }
  614. }
  615. }
  616. @Override
  617. public void keyReleased(KeyEvent e) {
  618. if(e.getKeyCode()==KeyEvent.VK_CONTROL){
  619. if(controlDown==true){
  620. controlDown = false;
  621. panel.repaint();
  622. }
  623. }
  624. }
  625. @Override
  626. public void mouseMoved(MouseEvent e) {
  627. /**
  628. * Link which might get a toolTip
  629. */
  630. Link l = null;
  631. /**
  632. * Check Hover on Link
  633. */
  634. if(config.isShowLinkToolTips())
  635. l = getLinkVisualizationAtPosition(e.getX(),e.getY());
  636. if(l != null){
  637. if(l != toolTip.getLink() || !toolTip.isEnabled()){
  638. toolTip.setText("Link "+l.getName());
  639. toolTip.setLink(l);
  640. toolTip.setX(e.getX());
  641. toolTip.setY(e.getY());
  642. toolTip.setEnabled(true);
  643. panel.update(null, null);
  644. }
  645. }else{
  646. if(toolTip.getLink()!=null || toolTip.isEnabled()){
  647. toolTip.setLink(null);
  648. toolTip.setEnabled(false);
  649. panel.update(null, null);
  650. }
  651. }
  652. }
  653. /**
  654. * Return Link which is at position at the given position
  655. * @param x xPosition
  656. * @param y yPosition
  657. * @return Link at the position, else null
  658. */
  659. private Link getLinkVisualizationAtPosition(int x, int y) {
  660. if(!config.isShowLinks())
  661. return null;
  662. // Check is device is inside visualization radius
  663. /**
  664. * Radius of the device
  665. */
  666. int smallRadius = config.getDeviceVisualizationRadius();
  667. /**
  668. * Radius of the device + link
  669. */
  670. int radius = smallRadius + config.getLinkRadius();
  671. for (SmartDevice d : network.getVisibleSmartDevices()) {
  672. //In DeviceRadius + Link Radius ?
  673. if (Math.abs(d.getX() - x) <= radius && Math.abs(d.getY() - y) <= radius) {
  674. //More detailed check
  675. // On Ring ?
  676. // On which part of Ring ?
  677. //Outside of device ?
  678. int realDistance = (int)Math.round(Math.sqrt((d.getX() - x)*(d.getX() - x)+(d.getY() - y)*(d.getY() - y)));
  679. if (realDistance >= smallRadius && realDistance <= radius && !d.getLinks().isEmpty()) {
  680. /**
  681. * Angle of this point. Counterclockwise, starting at 3 o' clock position
  682. */
  683. float angle = Utility.getAngle(d.getX(), d.getY(), x, y);
  684. /**
  685. * Number of Links in the Model
  686. */
  687. int numberOfLinks = network.getVisibleLinks().size();
  688. /**
  689. * Angle per Link in "linkSlice degrees"
  690. */
  691. double linkSlice = Math.min(360.0 / numberOfLinks,90.0);
  692. /**
  693. * calculate the number of the link
  694. */
  695. int linkNumber = (int) Math.floor(angle / linkSlice);
  696. /**
  697. * Return if, there are not so many link
  698. */
  699. if(linkNumber>=numberOfLinks)
  700. return null;
  701. /**
  702. * Link, which would be at this connection
  703. */
  704. Link linkAtPosition = (Link) network.getVisibleLinks().toArray()[linkNumber];
  705. /**
  706. * Return link, if smartDevice contains it
  707. */
  708. if(d.getLinks().contains(linkAtPosition))
  709. return linkAtPosition;
  710. }
  711. }
  712. }
  713. return null;
  714. }
  715. @Override
  716. public void mouseEntered(MouseEvent e) {}
  717. @Override
  718. public void mouseExited(MouseEvent e) {
  719. toolTip.setEnabled(false);
  720. }
  721. @Override
  722. public void actionPerformed(ActionEvent e) {}
  723. /**
  724. * Shows the RightClick Menu on the Visualization Panel, with Options for
  725. * the given SmartDevice clickedOn, if clickedOn is null, the RightClick
  726. * Menu contains Options for creation of new SmartDevices. The Menu will be
  727. * shown at the Mouse position on the VisualisationPanel.
  728. *
  729. * @param clickedOn
  730. * Device which was clicked, otherwise null
  731. * @param clickedLink Link which was clicked, otherwise null
  732. */
  733. protected void showRightClickMenu(SmartDevice clickedOn, Link clickedLink) {
  734. this.clickedLink = clickedLink;
  735. /**
  736. * Mouse Position on the VisualisationPanel
  737. */
  738. Point mousePos = panel.getMousePosition();
  739. // Just execute if Mouse Position is on the Panel
  740. if (mousePos != null) {
  741. if (clickedOn == null) {
  742. /**
  743. * Links which could be captured
  744. */
  745. LinkedList<Link> captureLinks = new LinkedList<Link>();
  746. if(clickedLink == null){
  747. itemCreateLink.setText("Create Link");
  748. if(selectionModel.selectedDevices.isEmpty())
  749. itemCreateLink.setEnabled(false);
  750. else
  751. itemCreateLink.setEnabled(true);
  752. }else{
  753. itemCreateLink.setText("Edit Link");
  754. itemCreateLink.setEnabled(true);
  755. captureLinks.add(clickedLink);
  756. }
  757. itemCreate.setText("Create Device");
  758. itemCreate.setEnabled(true);
  759. itemDelete.setEnabled(false);
  760. itemDeleteSelected.setEnabled(false);
  761. if(selectionModel.clickedConnection.size()>0){
  762. /**
  763. * Update Connections which can be edited
  764. */
  765. itemEditConnection.removeAll();
  766. //List to prevent duplicate connection entries
  767. LinkedList<Connection> editableConnections = new LinkedList<Connection>();
  768. for(Pair<Connection, Pair<Port,Port>> p:selectionModel.clickedConnection){
  769. //Don't add the same connection multiple times
  770. if(editableConnections.contains(p.getLeft())|| p == null || p.getLeft() == null)continue;
  771. editableConnections.add(p.getLeft());
  772. JMenuItem a = new JMenuItem(p.getLeft().getName());
  773. a.addActionListener(e->new ConnectionCreationDialog(p.getLeft(), controller, panel));
  774. itemEditConnection.add(a);
  775. }
  776. //Add Links of editable connections to the editLinks
  777. for(Connection c:editableConnections){
  778. if(c.getLink() != null && !captureLinks.contains(c.getLink()))
  779. captureLinks.add(c.getLink());
  780. }
  781. if(rightClickMenu.getComponentIndex(itemCreateConnection)!=-1){
  782. rightClickMenu.remove(itemCreateConnection);
  783. rightClickMenu.add(itemEditConnection,editCreateConnectionIndex);
  784. itemCreateConnection.setEnabled(false);
  785. }
  786. itemEditConnection.setEnabled(true);
  787. }else{
  788. if(rightClickMenu.getComponentIndex(itemEditConnection)!=-1){
  789. rightClickMenu.remove(itemEditConnection);
  790. rightClickMenu.add(itemCreateConnection,editCreateConnectionIndex);
  791. }
  792. if(selectionModel.selectedDevices.isEmpty()){
  793. itemCreateConnection.setEnabled(false);
  794. }else{
  795. itemCreateConnection.setEnabled(true);
  796. }
  797. }
  798. //Item capture
  799. itemCapture.removeAll();
  800. if(captureLinks.isEmpty()){
  801. itemCapture.setEnabled(false);
  802. }else{
  803. for(Link l: captureLinks){
  804. /**
  805. * Menu item to display a link which could be captured
  806. */
  807. JMenu currentLink = new JMenu(l.getName());
  808. for(PacketCollector collector: captureController.getPacketCollectors()){
  809. JMenuItem currentAlgorithm = new JMenuItem();
  810. String algoName;
  811. if(collector.getPacketAlgorithm()==null){
  812. algoName = "Null";
  813. }else{
  814. algoName = collector.getPacketAlgorithm().getClass().getSimpleName();
  815. }
  816. if(collector.getLinks().contains(l)){
  817. algoName += ": stop capture";
  818. currentAlgorithm.addActionListener(a->captureController.removeLinkFromCollector(collector, l));
  819. }else{
  820. algoName += ": start capture";
  821. currentAlgorithm.addActionListener(a->captureController.addLinkToCollector(collector, l));
  822. }
  823. currentAlgorithm.setText(algoName);
  824. currentLink.add(currentAlgorithm);
  825. }
  826. JMenuItem newCapture = new JMenuItem("Create new PacketCapturer");
  827. newCapture.addActionListener(a->{
  828. PacketCollector c = new PacketCollector();
  829. c.addLink(l);
  830. EditPacketSniffer popUp = new EditPacketSniffer(controller, panel, c, false);
  831. popUp.setVisible(true);
  832. });
  833. currentLink.add(newCapture);
  834. itemCapture.add(currentLink);
  835. }
  836. itemCapture.setEnabled(true);
  837. }
  838. } else {
  839. itemCreate.setText("Edit Device");
  840. itemCreate.setEnabled(true);
  841. itemDelete.setEnabled(true);
  842. //Remove edit connection if it exist
  843. if(rightClickMenu.getComponentIndex(itemEditConnection)!=-1){
  844. rightClickMenu.remove(itemEditConnection);
  845. rightClickMenu.add(itemCreateConnection,editCreateConnectionIndex);
  846. }
  847. itemCreateLink.setText("Create Link");
  848. itemCapture.removeAll();
  849. if(selectionModel.selectedDevices.contains(clickedOn)){
  850. itemDeleteSelected.setEnabled(true);
  851. itemCreateLink.setEnabled(true);
  852. itemCreateConnection.setEnabled(true);
  853. /**
  854. * Capture multiple
  855. */
  856. for(PacketCollector collector:captureController.getPacketCollectors()){
  857. JMenuItem itemCaptureDevice = new JMenuItem();
  858. String captureDeviceText = "";
  859. if(collector.getPacketAlgorithm()==null){
  860. captureDeviceText += "Null: ";
  861. }else{
  862. captureDeviceText += collector.getPacketAlgorithm().getClass().getSimpleName()+": ";
  863. }
  864. if(collector.getDevices().contains(clickedOn)){
  865. captureDeviceText += "stop capturing all";
  866. itemCaptureDevice.addActionListener(a->{
  867. for(SmartDevice d: selectionModel.selectedDevices)
  868. captureController.removeDeviceFromCollector(collector, d);
  869. });
  870. }else{
  871. captureDeviceText += "start capturing all";
  872. itemCaptureDevice.addActionListener(a->{
  873. for(SmartDevice d: selectionModel.selectedDevices)
  874. captureController.addDeviceToCollector(collector, d);
  875. });
  876. }
  877. itemCaptureDevice.setText(captureDeviceText);
  878. itemCapture.add(itemCaptureDevice);
  879. }
  880. itemCapture.setEnabled(true);
  881. JMenuItem newCapture = new JMenuItem("Create new PacketCapturer");
  882. newCapture.addActionListener(a->{
  883. PacketCollector c = new PacketCollector();
  884. for(SmartDevice d: selectionModel.selectedDevices)
  885. c.addDevice(d);
  886. EditPacketSniffer popUp = new EditPacketSniffer(controller, panel, c, false);
  887. popUp.setVisible(true);
  888. });
  889. itemCapture.add(newCapture);
  890. }
  891. else{
  892. itemDeleteSelected.setEnabled(false);
  893. itemCreateLink.setEnabled(false);
  894. itemCreateConnection.setEnabled(false);
  895. /**
  896. * Capture Single Device
  897. */
  898. for(PacketCollector collector:captureController.getPacketCollectors()){
  899. JMenuItem itemCaptureDevice = new JMenuItem();
  900. String captureDeviceText = "";
  901. if(collector.getPacketAlgorithm()==null){
  902. captureDeviceText += "Null: ";
  903. }else{
  904. captureDeviceText += collector.getPacketAlgorithm().getClass().getSimpleName()+": ";
  905. }
  906. if(collector.getDevices().contains(clickedOn)){
  907. captureDeviceText += "stop capture";
  908. itemCaptureDevice.addActionListener(a->captureController.removeDeviceFromCollector(collector, clickedOn));
  909. }else{
  910. captureDeviceText += "start capture";
  911. itemCaptureDevice.addActionListener(a->captureController.addDeviceToCollector(collector, clickedOn));
  912. }
  913. itemCaptureDevice.setText(captureDeviceText);
  914. itemCapture.add(itemCaptureDevice);
  915. }
  916. itemCapture.setEnabled(true);
  917. JMenuItem newCapture = new JMenuItem("Create new PacketCapturer");
  918. newCapture.addActionListener(a->{
  919. PacketCollector c = new PacketCollector();
  920. c.addDevice(clickedOn);
  921. EditPacketSniffer popUp = new EditPacketSniffer(controller, panel, c, false);
  922. popUp.setVisible(true);
  923. });
  924. itemCapture.add(newCapture);
  925. }
  926. }
  927. // Enable/Disable debug print out
  928. itemDebug.setVisible(config.isDebugModus());
  929. // Show the RightClickMenu
  930. rightClickMenu.show(panel, mousePos.x, mousePos.y);
  931. rightClickMenu.setEnabled(true);
  932. rightClickMenu.setVisible(true);
  933. mode = RIGHTCLICK_MENU;
  934. }
  935. }
  936. /**
  937. * Creates the RightClickMenu, adds the different Labels and functionalities to the menu and adds it to the panel.
  938. */
  939. private void initializeRightClickMenu() {
  940. this.rightClickMenu = new JPopupMenu();
  941. // Create device option
  942. itemCreate = new JMenuItem("Create SmartDevice");
  943. itemCreate.addActionListener(e -> {
  944. SmartDevice toEdit;
  945. if(clicked == null){
  946. toEdit = new SmartDevice("DeviceName");
  947. toEdit.setX(dragged_x);
  948. toEdit.setY(dragged_y);
  949. }else{
  950. toEdit = clicked;
  951. }
  952. SmartDeviceCreationPopUp popUp = new SmartDeviceCreationPopUp(toEdit, toEdit==clicked,controller);
  953. popUp.setLocationRelativeTo(panel);
  954. popUp.setEnabled(true);
  955. popUp.setVisible(true);
  956. mode = NOTHING;
  957. });
  958. rightClickMenu.add(itemCreate);
  959. // Create Link
  960. itemCreateLink = new JMenuItem("Create Link");
  961. itemCreateLink.addActionListener(e -> {
  962. if(clickedLink!=null){
  963. new LinkCreationDialog(clickedLink, controller, panel);
  964. }else{
  965. new LinkCreationDialog(selectionModel.selectedDevices, controller, panel);
  966. }
  967. if(selectionModel.selectedDevices.isEmpty())
  968. mode = NOTHING;
  969. else
  970. mode = SELECTED;
  971. });
  972. rightClickMenu.add(itemCreateLink);
  973. // Create Connection
  974. itemCreateConnection = new JMenuItem("Create Connection");
  975. itemCreateConnection.addActionListener(e->{
  976. LinkedList<SmartDevice> selectedDevices = new LinkedList<SmartDevice>(selectionModel.selectedDevices);
  977. new ConnectionCreationDialog(selectedDevices, controller, panel);
  978. if(selectionModel.selectedDevices.isEmpty())
  979. mode = NOTHING;
  980. else
  981. mode = SELECTED;
  982. });
  983. rightClickMenu.add(itemCreateConnection);
  984. // Edit connection
  985. itemEditConnection = new JMenu("Edit Connection");
  986. rightClickMenu.add(itemEditConnection);
  987. //Capture packets
  988. itemCapture = new JMenu("Capture Packets");
  989. rightClickMenu.add(itemCapture);
  990. // Delete device option
  991. itemDelete = new JMenuItem("Delete");
  992. itemDelete.addActionListener(e -> {
  993. // Delete the clicked object
  994. network.deleteSmartDevice(clicked);
  995. clicked = null;
  996. controller.notifyObservers();
  997. mode = NOTHING;
  998. });
  999. rightClickMenu.add(itemDelete);
  1000. // Delete device option
  1001. itemDeleteSelected = new JMenuItem("Delete Selected");
  1002. itemDeleteSelected.addActionListener(e -> {
  1003. // Delete the clicked object
  1004. for(SmartDevice c: selectionModel.selectedDevices)
  1005. network.deleteSmartDevice(c);
  1006. selectionModel.selectedDevices.clear();
  1007. clicked = null;
  1008. controller.notifyObservers();
  1009. mode = NOTHING;
  1010. });
  1011. itemDeleteSelected.setEnabled(false);
  1012. rightClickMenu.add(itemDeleteSelected);
  1013. /*
  1014. * Add PrintDebug option
  1015. */
  1016. itemDebug = new JMenuItem("Print NetworkState");
  1017. itemDebug.addActionListener(e -> {
  1018. // Print Links, Devices and Connections
  1019. System.out.println("Links:");
  1020. for (Link l : network.getLinks()){
  1021. System.out.println("Link: " + l.getName());
  1022. System.out.print("Devices of "+l.getName()+": ");
  1023. for(SmartDevice d:l.getDevices())
  1024. System.out.print(d.getName()+", ");
  1025. System.out.println();
  1026. System.out.print("Connections of "+l.getName()+": ");
  1027. for(Connection c: l.getConnections())
  1028. System.out.print(c.getName()+", ");
  1029. System.out.println();
  1030. }
  1031. System.out.println();
  1032. System.out.println("Devices");
  1033. for (SmartDevice d : network.getSmartDevices()) {
  1034. System.out.println("Device: " + d.getName());
  1035. System.out.println("Ports: ");
  1036. for (Port p : d.getPorts()) {
  1037. if(p==null){
  1038. System.out.println("Port: null");
  1039. continue;
  1040. }
  1041. System.out.println("Port: "+p.getPortNumber());
  1042. if(p.getOwner()!=null)
  1043. System.out.println("Owner: "+p.getOwner().getName());
  1044. else
  1045. System.out.println("Owner: null");
  1046. if(p.getConnection()==null){
  1047. System.out.println("Connection: null");
  1048. }else{
  1049. System.out.println("Connection: "+p.getConnection().getName());
  1050. }
  1051. System.out.println("LastTrigger: " +p.getLastTrigger());
  1052. System.out.println("Jitter: " +p.getJitter());
  1053. System.out.println("ResponseTime: " +p.getResponseTime());
  1054. System.out.println("TriggerInterval: " +p.getTriggerInterval());
  1055. System.out.println("Status: " +Port.statusToString(p.getStatus()));
  1056. System.out.println();
  1057. }
  1058. System.out.println("");
  1059. }
  1060. // Print Terminating Packages
  1061. LinkedList<Connection> terminated = new LinkedList<Connection>();
  1062. network.getConnections()
  1063. .stream()
  1064. .forEach(c -> {
  1065. if(c.getStatus() == Connection.FINISHED || c
  1066. .getStatus() == Connection.TERMINATED)
  1067. terminated.add(c);
  1068. for (Packet p : c.getTerminationPackages(1000))
  1069. System.out.println(p.getTextualRepresentation());
  1070. });
  1071. network.getConnections().removeAll(terminated);
  1072. if(selectionModel.selectedDevices.isEmpty())
  1073. mode = NOTHING;
  1074. else
  1075. mode = SELECTED;
  1076. controller.notifyObservers();
  1077. });
  1078. rightClickMenu.add(itemDebug);
  1079. this.panel.add(rightClickMenu);
  1080. }
  1081. /**
  1082. * @return the toolTip
  1083. */
  1084. public LinkToolTip getToolTip() {
  1085. return toolTip;
  1086. }
  1087. }