001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.ecoinformatics.seek.querybuilder; 031 032import java.awt.Color; 033import java.awt.Graphics; 034import java.awt.Polygon; 035import java.awt.Rectangle; 036import java.awt.event.MouseEvent; 037import java.util.Enumeration; 038import java.util.Vector; 039 040import javax.swing.SwingUtilities; 041 042import org.kepler.objectmanager.data.db.DSSchemaIFace; 043 044/** 045 * This class maintains all the joins for the query. It is a model, a view, and 046 * a controller.<br> 047 * Model - A vector of all the join items<br> 048 * View - It is responsible for drawing all the lines representing the joins 049 * Controller - When clicks occur it is asked for hit detection as to whether a 050 * link was clicked on. 051 */ 052public class DBTableJoin { 053 private static final int LINE_LEN = 10; 054 private static final int TRI_SIZE = 3; 055 056 private int[] xArray = new int[5]; 057 private int[] yArray = new int[5]; 058 059 protected Vector mJoinItems = new Vector(); 060 protected DSSchemaIFace mSchema = null; 061 protected DBTableDesktopPane mDesktopPane = null; 062 protected DBTableJoinItem mSelectedItem = null; 063 064 /** 065 * Constructor takes Schema object (interface) 066 * 067 * @param aDeskTopPane 068 * desktop pane that implements DSSchemaIFace 069 */ 070 public DBTableJoin(DBTableDesktopPane aDeskTopPane) { 071 mDesktopPane = aDeskTopPane; 072 mSchema = (DSSchemaIFace) mDesktopPane; 073 } 074 075 /** 076 * Returns the Vector of Joins 077 * 078 * @return vector 079 */ 080 public Vector getJoins() { 081 return mJoinItems; 082 } 083 084 /** 085 * Clears all of the join items 086 * 087 */ 088 public void clear() { 089 for (Enumeration e = mJoinItems.elements(); e.hasMoreElements();) { 090 DBTableJoinItem joinItem = (DBTableJoinItem) e.nextElement(); 091 joinItem.mItemLeft.setLinked(false); 092 joinItem.mItemRight.setLinked(false); 093 ; 094 } 095 mJoinItems.clear(); 096 } 097 098 /** 099 * 100 * @param aItem 101 * @param aTableId 102 * @param aTableName 103 * */ 104 private boolean isTableMatch(DBTableField aItem, int aTableId, 105 String aTableName) { 106 return ((aTableId != -1 && aItem.getTable().getId() == aTableId) || (aTableId == -1 && aTableName 107 .equals(aItem.getTable().getName()))); 108 } 109 110 /** 111 * Removes a tables to and from joins. It looks up by id first and then 112 * table name 113 * 114 * @param aTableId 115 * the id of the table 116 * @param aTableName 117 * the name of the table 118 */ 119 public void removeTable(int aTableId, String aTableName) { 120 // System.out.println("Removing table: "+aTableId+" "+aTableName); 121 // first collect all the join items to be removed 122 Vector joinsToRemove = new Vector(); 123 for (Enumeration e = mJoinItems.elements(); e.hasMoreElements();) { 124 DBTableJoinItem joinItem = (DBTableJoinItem) e.nextElement(); 125 if (isTableMatch(joinItem.mItemLeft, aTableId, aTableName) 126 || isTableMatch(joinItem.mItemRight, aTableId, aTableName)) { 127 // System.out.println("Removing join: "+joinItem.mItemLeft.getTable().getId()+" "+joinItem.mItemLeft.getTable().getName()); 128 // System.out.println(" "+joinItem.mItemRight.getTable().getId()+" "+joinItem.mItemRight.getTable().getName()); 129 joinsToRemove.add(joinItem); 130 } 131 } 132 // now remove all the join items we have collected 133 for (Enumeration e = joinsToRemove.elements(); e.hasMoreElements();) { 134 mJoinItems.remove((DBTableJoinItem) e.nextElement()); 135 } 136 } 137 138 /** 139 * Add a Join 140 * 141 * @param aItem1 142 * the left item 143 * @param aItem2 144 * the right item 145 */ 146 public void addJoin(DBTableField aItem1, DBTableField aItem2) { 147 if (aItem1 != null && aItem2 != null) { 148 DBTableJoinItem item = new DBTableJoinItem(aItem1, aItem2); 149 150 aItem1.setLinked(true); 151 aItem2.setLinked(true); 152 mJoinItems.add(item); 153 } 154 } 155 156 /** 157 * Add a Join by item 158 * 159 * @param aLeft 160 * the left part of the link 161 * @param aRight 162 * the right part of the link 163 */ 164 public void addJoin(DBSelectTableModelItem aLeft, 165 DBSelectTableModelItem aRight) { 166 DBTableField field1 = mDesktopPane.getFieldById(aLeft); 167 DBTableField field2 = mDesktopPane.getFieldById(aRight); 168 if (field1 != null && field2 != null) { 169 addJoin(field1, field2); 170 } 171 } 172 173 /** 174 * Helper class for debugging 175 * 176 * @param aMsg 177 * the text 178 * @param r 179 * the rect 180 */ 181 /* 182 * protected void printRect(String aMsg, Rectangle r){ 183 * System.out.print(aMsg+" ["+r.x+","+r.y+","+r.width+","+r.height+"]"); } 184 */ 185 186 /** 187 * Implements a paint method for painting all joins 188 * 189 * @param g 190 * the graphics object 191 */ 192 public void paint(Graphics g) { 193 for (Enumeration e = mJoinItems.elements(); e.hasMoreElements();) { 194 DBTableJoinItem joinItem = (DBTableJoinItem) e.nextElement(); 195 DBTableField item1 = joinItem.mItemLeft; 196 DBTableField item2 = joinItem.mItemRight; 197 198 DBTableFrame tableFrame1 = item1.getTable(); 199 DBTableFrame tableFrame2 = item2.getTable(); 200 201 int val1 = tableFrame1.getScrollValue(); 202 int val2 = tableFrame2.getScrollValue(); 203 204 Rectangle tfListRect1 = tableFrame1.getListBounds(); 205 Rectangle tfListRect2 = tableFrame2.getListBounds(); 206 Rectangle tfBnds1 = tableFrame1.getBounds(); 207 Rectangle tfBnds2 = tableFrame2.getBounds(); 208 209 Rectangle r1 = item1.getBounds(); 210 Rectangle r2 = item2.getBounds(); 211 // printRect("r1 ", r1); 212 // System.out.println(" "); 213 // printRect("r2 ", r2); 214 // System.out.println(" "); 215 216 r1.x = tfBnds1.x; 217 r1.width = tfBnds1.width; 218 int y = r1.y - val1; 219 if (y < 0) { 220 r1.setBounds(tfBnds1.x, tfBnds1.y + 5, tfBnds1.width, 1); 221 } else if (y > tfListRect1.height) { 222 r1.setBounds(tfBnds1.x, tfBnds1.y + tfBnds1.height - 1 - 5, 223 tfBnds1.width, 1); 224 } else { 225 r1.y = y + tfListRect1.y + tfBnds1.y; 226 } 227 228 r2.x = tfBnds2.x; 229 r2.width = tfBnds2.width; 230 231 y = r2.y - val2; 232 if (y < 0) { 233 r2.setBounds(tfBnds2.x, tfBnds2.y + 5, tfBnds2.width, 2); 234 235 } else if (y > tfListRect2.height) { 236 r2.setBounds(tfBnds2.x, tfBnds2.y + tfBnds2.height - 2 - 5, 237 tfBnds2.width, 2); 238 239 } else { 240 r2.y = y + tfListRect2.y + tfBnds2.y; 241 } 242 243 int r1HalfX = (int) r1.getCenterX(); 244 int r1HalfY = (int) r1.getCenterY(); 245 int r2HalfX = (int) r2.getCenterX(); 246 int r2HalfY = (int) r2.getCenterY(); 247 248 int r1Right = r1.x + r1.width; 249 int r2Right = r2.x + r2.width; 250 251 g.setColor(joinItem.isSelected() ? Color.yellow : Color.blue); 252 253 if (r1.x > r2Right || r1.x >= r2.x && r1.x <= r2Right) { 254 int xPntsRight[] = { r1.x, r1.x - TRI_SIZE, r1.x }; 255 int yPntsRight[] = { r1HalfY - TRI_SIZE, r1HalfY, 256 r1HalfY + TRI_SIZE }; 257 int xPntsLeft[] = { r2Right, r2Right + TRI_SIZE, r2Right }; 258 int yPntsLeft[] = { r2HalfY + TRI_SIZE, r2HalfY, 259 r2HalfY - TRI_SIZE }; 260 261 g.setColor(joinItem.isSelected() ? Color.yellow : Color.red); 262 g.fillPolygon(xPntsRight, yPntsRight, 3); 263 g.drawLine(r1.x, r1HalfY, r1.x - LINE_LEN, r1HalfY); 264 g.drawLine(r1.x - LINE_LEN, r1HalfY, r2Right + LINE_LEN, 265 r2HalfY); 266 g.drawLine(r2Right + LINE_LEN, r2HalfY, r2Right, r2HalfY); 267 g.fillPolygon(xPntsLeft, yPntsLeft, 3); 268 269 joinItem.changePolygon(0, r1.x, r1HalfY, r1.x - LINE_LEN, 270 r1HalfY); 271 joinItem.changePolygon(1, r1.x - LINE_LEN, r1HalfY, r2Right 272 + LINE_LEN, r2HalfY); 273 joinItem.changePolygon(2, r2Right + LINE_LEN, r2HalfY, r2Right, 274 r2HalfY); 275 276 } else if (r2.x > r1Right || r2.x >= r1.x && r2.x <= r1Right) { 277 int xPntsRight[] = { r2.x, r2.x - TRI_SIZE, r2.x }; 278 int yPntsRight[] = { r2HalfY - TRI_SIZE, r2HalfY, 279 r2HalfY + TRI_SIZE }; 280 int xPntsLeft[] = { r1Right, r1Right + TRI_SIZE, r1Right }; 281 int yPntsLeft[] = { r1HalfY + TRI_SIZE, r1HalfY, 282 r1HalfY - TRI_SIZE }; 283 284 g.fillPolygon(xPntsLeft, yPntsLeft, 3); 285 g.drawLine(r2.x, r2HalfY, r2.x - LINE_LEN, r2HalfY); 286 g.drawLine(r2.x - LINE_LEN, r2HalfY, r1Right + LINE_LEN, 287 r1HalfY); 288 g.drawLine(r1Right + LINE_LEN, r1HalfY, r1Right, r1HalfY); 289 g.fillPolygon(xPntsRight, yPntsRight, 3); 290 291 joinItem.changePolygon(0, r2.x, r2HalfY, r2.x - LINE_LEN, 292 r2HalfY); 293 joinItem.changePolygon(1, r2.x - LINE_LEN, r2HalfY, r1Right 294 + LINE_LEN, r1HalfY); 295 joinItem.changePolygon(2, r1Right + LINE_LEN, r1HalfY, r1Right, 296 r1HalfY); 297 } 298 299 // debug only do not remove 300 /* 301 * Polygon[] p = joinItem.getPolygons(); g.setColor(Color.red); 302 * g.drawPolygon(p[0]); g.setColor(Color.green); 303 * g.drawPolygon(p[1]); g.setColor(Color.magenta); 304 * g.drawPolygon(p[2]); 305 */ 306 307 } 308 } 309 310 /** 311 * Refreshes the DesktopPane 312 */ 313 public void refresh() { 314 mDesktopPane.makeDirty(); 315 } 316 317 /** 318 * Removes a link or "join" between two tables 319 * 320 * @return true if link was deleted, false if not 321 */ 322 public boolean removeSelectedLink() { 323 if (mSelectedItem != null) { 324 mJoinItems.remove(mSelectedItem); 325 mSelectedItem = null; 326 refresh(); 327 return true; 328 } 329 return false; 330 } 331 332 /** 333 * Uses the mouse event to select or deselect a link 334 * 335 * @param ev 336 * mouse event 337 */ 338 public void selectLink(MouseEvent ev) { 339 DBTableJoinItem oldSelectedItem = mSelectedItem; 340 DBTableJoinItem newSelectedItem = null; 341 342 for (Enumeration e = mJoinItems.elements(); e.hasMoreElements();) { 343 DBTableJoinItem joinItem = (DBTableJoinItem) e.nextElement(); 344 Polygon[] polygons = joinItem.getPolygons(); 345 for (int i = 0; i < polygons.length; i++) { 346 if (polygons[i].contains(ev.getPoint())) { 347 newSelectedItem = joinItem; 348 break; 349 } 350 } 351 } 352 353 if (newSelectedItem != null) { 354 if (newSelectedItem == oldSelectedItem) { 355 newSelectedItem.setIsSelected(!newSelectedItem.isSelected()); 356 } else { 357 if (mSelectedItem != null) { 358 mSelectedItem.setIsSelected(false); 359 } 360 newSelectedItem.setIsSelected(true); 361 362 mSelectedItem = newSelectedItem; 363 // Make sure a list has focus so the delete key can be properly 364 // processed 365 SwingUtilities.invokeLater(new Runnable() { 366 public void run() { 367 mDesktopPane.getDesktopManager().activateFrame( 368 mSelectedItem.getItemLeft().getTable()); 369 mSelectedItem.getItemLeft().getTable().getList() 370 .requestFocus(); 371 } 372 }); 373 } 374 } else { 375 if (mSelectedItem != null) { 376 mSelectedItem.setIsSelected(false); 377 mSelectedItem = null; 378 } 379 } 380 refresh(); 381 } 382 383}