AbstractCanvas.java.orig 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. package ui.view;
  2. import java.awt.BasicStroke;
  3. import java.awt.Color;
  4. import java.awt.Graphics;
  5. import java.awt.Graphics2D;
  6. import java.awt.Image;
  7. import java.awt.Point;
  8. import java.awt.event.MouseEvent;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.TimerTask;
  12. import javax.swing.CellEditor;
  13. import javax.swing.JMenuItem;
  14. import javax.swing.JPanel;
  15. import javax.swing.JPopupMenu;
  16. import javax.swing.JTable;
  17. import javax.swing.Timer;
  18. import classes.AbstractCanvasObject;
  19. import classes.Edge;
  20. import classes.GroupNode;
  21. import classes.HolonElement;
  22. import classes.HolonObject;
  23. import classes.Node;
  24. import ui.controller.Control;
  25. import ui.controller.UpdateController;
  26. import ui.model.Model;
  27. import utility.Vector2Int;
  28. /**
  29. * Collection of methods and values needed in both <code>MyCanvas</code> and
  30. * <code>UpperNodeCanvas</code>
  31. * <p>
  32. * Although Java works on references we chose to add explicit return values for
  33. * clearer code understanding in most cases
  34. *
  35. * @author: I. Dix
  36. */
  37. public abstract class AbstractCanvas extends JPanel {
  38. /**
  39. * Version
  40. */
  41. private static final long serialVersionUID = 1L;
  42. final JMenuItem itemCut = new JMenuItem("Cut");
  43. final JMenuItem itemCopy = new JMenuItem("Copy");
  44. final JMenuItem itemPaste = new JMenuItem("Paste");
  45. final JMenuItem itemDelete = new JMenuItem("Delete");
  46. final JMenuItem itemGroup = new JMenuItem("Group");
  47. final JMenuItem itemUngroup = new JMenuItem("Ungroup");
  48. final JMenuItem itemAlign = new JMenuItem("Align selected");
  49. final JMenuItem itemCreateTemplate = new JMenuItem("Create Template");
  50. final int ANIMTIME = 500; // animation Time
  51. private final int animFPS = 60;
  52. final int animDelay = 1000 / animFPS; // animation Delay
  53. protected Model model;
  54. protected Control controller;
  55. protected int x = 0;
  56. protected int y = 0;
  57. // Selection
  58. AbstractCanvasObject tempCps = null;
  59. UpdateController updCon;
  60. //Replacement
  61. /**
  62. * the CpsObject that might be replaced by drag&drop
  63. */
  64. protected AbstractCanvasObject mayBeReplaced = null;
  65. // PopUpMenu
  66. JPopupMenu popmenu = new JPopupMenu();
  67. // Tooltip
  68. boolean toolTip; // Tooltip on or off
  69. Vector2Int toolTipPos = new Vector2Int(); // Tooltip Position
  70. String toolTipText = "";
  71. List<HolonElement> dataSelected = new ArrayList<>();
  72. ArrayList<AbstractCanvasObject> tempSelected = new ArrayList<>();
  73. boolean[] showedInformation = new boolean[5];
  74. boolean showConnectionInformation;
  75. boolean dragging = false; // for dragging
  76. boolean dragged = false; // if an object/objects was/were dragged
  77. boolean drawEdge = false; // for drawing edges
  78. boolean doMark = false; // for double click
  79. Edge edgeHighlight = null;
  80. Point mousePosition = new Point(); // Mouse Position when
  81. ArrayList<Vector2Int> savePos;
  82. // edge Object Start Point
  83. int cx, cy;
  84. int sx, sy; // Mark Coords
  85. Vector2Int unPos;
  86. // Animation
  87. Timer animT; // animation Timer
  88. int animDuration = ANIMTIME; // animation Duration
  89. int animSteps = animDuration / animDelay; // animation Steps;
  90. ArrayList<AbstractCanvasObject> animCps = null;
  91. // Graphics
  92. Image img = null; // Contains the image to draw on the Canvas
  93. Graphics2D g2; // For Painting
  94. float scalediv20;
  95. // Mouse
  96. private boolean click = false;
  97. // ------------------------------------------ METHODS
  98. // ------------------------------------------
  99. class ACpsHandle{
  100. public AbstractCanvasObject object;
  101. ACpsHandle(AbstractCanvasObject object){
  102. this.object = object;
  103. }
  104. public String toString() {
  105. return object.toString();
  106. }
  107. }
  108. void drawMarker() {
  109. if (sx > x && sy > y) {
  110. g2.drawRect(x, y, sx - x, sy - y);
  111. } else if (sx < x && sy < y) {
  112. g2.drawRect(sx, sy, x - sx, y - sy);
  113. } else if (sx >= x) {
  114. g2.drawRect(x, sy, sx - x, y - sy);
  115. } else if (sy >= y) {
  116. g2.drawRect(sx, y, x - sx, sy - y);
  117. }
  118. }
  119. /**
  120. * @deprecated
  121. * @param g
  122. */
  123. void showTooltip(Graphics g) {
  124. if (toolTip) {
  125. g2.setColor(new Color(255, 225, 150));
  126. g2.setStroke(new BasicStroke(1));
  127. int textWidth = g.getFontMetrics().stringWidth(toolTipText) + 2; // Text
  128. // width
  129. // fixed x and y Position to the screen
  130. int fixXPos = toolTipPos.getX() - (textWidth >> 1) + model.getScaleDiv2();
  131. int fixYPos = toolTipPos.getY();
  132. if (fixXPos < 0) {
  133. fixXPos = 0;
  134. } else if (fixXPos + textWidth + 1 > this.getWidth()) {
  135. fixXPos -= (fixXPos + textWidth + 1) - this.getWidth();
  136. }
  137. if (fixYPos + 16 > this.getHeight()) {
  138. fixYPos -= (fixYPos + 16) - this.getHeight();
  139. }
  140. g2.fillRect(fixXPos, fixYPos, textWidth, 15);
  141. g2.setColor(Color.BLACK);
  142. g2.drawRect(fixXPos, fixYPos, textWidth, 15);
  143. g2.drawString(toolTipText, fixXPos + 2, fixYPos + 12);
  144. }
  145. }
  146. void setRightClickMenu(MouseEvent e) {
  147. if (e.getButton() == MouseEvent.BUTTON3) {
  148. itemPaste.setEnabled(true);
  149. if (tempCps != null) {
  150. itemPaste.setEnabled(true);
  151. itemDelete.setEnabled(true);
  152. itemCut.setEnabled(true);
  153. itemCopy.setEnabled(true);
  154. itemAlign.setEnabled(true);
  155. // tracking
  156. if (tempCps != null) {
  157. itemGroup.setEnabled(true);
  158. }
  159. // ungrouping
  160. if (tempCps instanceof GroupNode)
  161. itemUngroup.setEnabled(true);
  162. else
  163. itemUngroup.setEnabled(false);
  164. if (model.getSelectedCpsObjects().size() == 0) {
  165. controller.addSelectedObject(tempCps);
  166. }
  167. if (tempCps instanceof HolonObject) {
  168. itemCreateTemplate.setEnabled(true);
  169. } else {
  170. itemCreateTemplate.setEnabled(false);
  171. }
  172. } else {
  173. itemAlign.setEnabled(false);
  174. itemCut.setEnabled(false);
  175. itemCopy.setEnabled(false);
  176. itemGroup.setEnabled(false);
  177. itemUngroup.setEnabled(false);
  178. itemCreateTemplate.setEnabled(false);
  179. if (edgeHighlight != null) {
  180. itemDelete.setEnabled(true);
  181. itemPaste.setEnabled(false);
  182. } else {
  183. itemDelete.setEnabled(false);
  184. itemPaste.setEnabled(true);
  185. }
  186. }
  187. mousePosition = this.getMousePosition();
  188. popmenu.show(e.getComponent(), e.getX(), e.getY());
  189. }
  190. }
  191. void markObjects() {
  192. if (doMark) {
  193. doMark = false;
  194. for (AbstractCanvasObject cps : tempSelected) {
  195. if (!model.getSelectedCpsObjects().contains(cps)) {
  196. controller.addSelectedObject(cps);
  197. }
  198. }
  199. controller.getObjectsInDepth();
  200. tempSelected.clear();
  201. }
  202. }
  203. int[] determineMousePositionOnEdge(Edge p) {
  204. int lx, ly, hx, hy;
  205. if (p.getA().getPosition().getX() > p.getB().getPosition().getX()) {
  206. hx = p.getA().getPosition().getX() + model.getScaleDiv2() + 7;
  207. lx = p.getB().getPosition().getX() + model.getScaleDiv2() - 7;
  208. } else {
  209. lx = p.getA().getPosition().getX() + model.getScaleDiv2() - 7;
  210. hx = p.getB().getPosition().getX() + model.getScaleDiv2() + 7;
  211. }
  212. if (p.getA().getPosition().getY() > p.getB().getPosition().getY()) {
  213. hy = p.getA().getPosition().getY() + model.getScaleDiv2() + 7;
  214. ly = p.getB().getPosition().getY() + model.getScaleDiv2() - 7;
  215. } else {
  216. ly = p.getA().getPosition().getY() + model.getScaleDiv2() - 7;
  217. hy = p.getB().getPosition().getY() + model.getScaleDiv2() + 7;
  218. }
  219. return new int[] { lx, ly, hx, hy };
  220. }
  221. /**
  222. * Checks if a double click was made.
  223. *
  224. * @return true if doublecklick, false if not
  225. */
  226. boolean doubleClick() {
  227. if (click) {
  228. click = false;
  229. return true;
  230. } else {
  231. click = true;
  232. java.util.Timer t = new java.util.Timer("doubleclickTimer", false);
  233. t.schedule(new TimerTask() {
  234. @Override
  235. public void run() {
  236. click = false;
  237. }
  238. }, 500);
  239. }
  240. return false;
  241. }
  242. boolean setToolTipInfoAndPosition(boolean on, AbstractCanvasObject cps) {
  243. if (x - controller.getScale() <= cx && y - controller.getScale() <= cy && x >= cx && y >= cy) {
  244. on = true;
  245. toolTipPos.setX(cps.getPosition().getX() - controller.getScaleDiv2());
  246. toolTipPos.setY(cps.getPosition().getY() + controller.getScaleDiv2());
  247. toolTipText = cps.getName() + ", " + cps.getId();
  248. }
  249. return on;
  250. }
  251. abstract void drawDeleteEdge();
  252. void triggerUpdateController() {
  253. updCon.paintProperties(tempCps);
  254. updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
  255. updCon.refreshTableProperties(model.getPropertyTable());
  256. }
  257. /**
  258. * Checks if {@code draggedCps} or a new cpsObject at Position (x,y) could replace exactly one object
  259. * in {@code objects}.
  260. * Saves the object that would be replaced in {@link AbstractCanvas}.{@code MayBeReplaced}
  261. * @param objects list of objects that could be replaced
  262. * @param draggedCps Object that might replace
  263. * @param x Position of the objects that might replace
  264. * @param y Position of the objects that might replace
  265. * @return true if exactly one Object could be replaced
  266. */
  267. protected boolean checkForReplacement(ArrayList<AbstractCanvasObject> objects, AbstractCanvasObject draggedCps, int x, int y){
  268. /** distance treshold for replacement */
  269. int treshhold = controller.getScale()/2;
  270. /** number of Objects that might be replaced (should be 1) */
  271. int replaceCounter = 0;
  272. /** last object that could be replaced */
  273. AbstractCanvasObject toBeReplaced = null;
  274. /** Position of object that might be replaced */
  275. Vector2Int p;
  276. /** for each cps on Canvas */
  277. if(draggedCps == null || !(draggedCps instanceof Node) && !(draggedCps instanceof Node)){
  278. for (AbstractCanvasObject cps : objects){
  279. /** same object -> ignore */
  280. if(cps == draggedCps)continue;
  281. /** set Position of object that might be replaced */
  282. p = cps.getPosition();
  283. /** if near enough */
  284. if(Math.abs(x-p.getX())<treshhold && Math.abs(y-p.getY())<treshhold){
  285. replaceCounter++;
  286. toBeReplaced = cps;
  287. /**
  288. * if too many Objects could be replaced:
  289. * stop searching, because it would not be clear which one should
  290. * be replaced
  291. */
  292. if(replaceCounter>1)break;
  293. }
  294. }
  295. }
  296. /**
  297. * return true if exactly one obect would be replaced
  298. */
  299. if( replaceCounter == 1 && toBeReplaced != null){
  300. mayBeReplaced = toBeReplaced;
  301. return true;
  302. }else{
  303. mayBeReplaced = null;
  304. return false;
  305. }
  306. }
  307. /**
  308. * Checks if an inserted new Object could replace exactly one object on the canvas.
  309. * Saves the object that would be replaced in {@link AbstractCanvas}.{@code MayBeReplaced}
  310. * @param x Position of the objects that might replace
  311. * @param y Position of the objects that might replace
  312. * @return true if exactly one Object could be replaced
  313. */
  314. public abstract boolean checkForReplacement(int x, int y);
  315. /**
  316. * highlights the object that mayBeReplaced
  317. * @param g2
  318. */
  319. protected void highlightMayBeReplaced(Graphics2D g2) {
  320. if(mayBeReplaced != null){
  321. g2.setColor(Color.RED);
  322. g2.fillRect(
  323. (int) (mayBeReplaced.getPosition().getX()
  324. - controller.getScaleDiv2() - (scalediv20 + 3)),
  325. (int) (mayBeReplaced.getPosition().getY()
  326. - controller.getScaleDiv2() - (scalediv20 + 3)),
  327. (int) (controller.getScale() + ((scalediv20 + 3) * 2)),
  328. (int) (controller.getScale() + ((scalediv20 + 3) * 2)));
  329. }
  330. }
  331. /**
  332. * Align alle Objects on the Canvas to a Grid with objects every 10 pixels
  333. */
  334. public abstract void tryToAlignObjects();
  335. /**
  336. * Aligns the Object the a grid
  337. * @param cps Object that should be aligned
  338. * @param distance distance between the AlignmentGrid Lines. (objects every 'distance' pixels
  339. */
  340. protected void align(AbstractCanvasObject cps, int distance) {
  341. /** Position of the AbstractCpsObject which should be aligned */
  342. Vector2Int p = cps.getPosition();
  343. //calculate how many pixels the cps should be decreased to align
  344. /** x offset relative to a grid with lines every distance pixels */
  345. int x_off = cps.getPosition().getX() % distance;
  346. /** y offset relative to a grid with lines every distance pixels */
  347. int y_off = cps.getPosition().getY() % distance;
  348. //align to the other Line, if it is nearer
  349. if(x_off > distance/2)
  350. x_off -= distance;
  351. if(y_off > distance/2)
  352. y_off -= distance;
  353. /** set new Position */
  354. cps.setPosition(p.getX()-x_off, p.getY()-y_off);
  355. }
  356. /**
  357. * Stops Editing in HolonElementTable and PropertyTable
  358. */
  359. protected void stopEditing() {
  360. /**
  361. * Stop Editing, if mouse exits the Table
  362. */
  363. JTable holElem = model.getTableHolonElement();
  364. CellEditor cellEditor = holElem.getCellEditor();
  365. if (cellEditor != null) {
  366. if (cellEditor.getCellEditorValue() != null) {
  367. /** TODO: Maybe try to save current Data */
  368. cellEditor.stopCellEditing();
  369. } else {
  370. cellEditor.cancelCellEditing();
  371. }
  372. }
  373. }
  374. /**
  375. * Closes a tab of the UpperNode with ID upperNodeID
  376. * @param upperNodeId
  377. */
  378. public abstract void closeUpperNodeTab(int upperNodeId);
  379. }