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.Component; 033import java.awt.Dimension; 034import java.awt.Graphics; 035import java.awt.Rectangle; 036import java.awt.event.KeyAdapter; 037import java.awt.event.KeyEvent; 038import java.awt.event.KeyListener; 039import java.awt.event.MouseAdapter; 040import java.awt.event.MouseEvent; 041import java.awt.event.MouseListener; 042import java.util.Enumeration; 043import java.util.Hashtable; 044import java.util.Vector; 045 046import javax.swing.JComponent; 047import javax.swing.JDesktopPane; 048import javax.swing.RepaintManager; 049import javax.swing.SwingUtilities; 050import javax.swing.event.InternalFrameEvent; 051import javax.swing.event.InternalFrameListener; 052import javax.swing.event.TableModelListener; 053 054import org.kepler.objectmanager.data.db.DSSchemaIFace; 055import org.kepler.objectmanager.data.db.DSTableIFace; 056 057/** 058 * Overrides JDesktopPane for laying out all the tables 059 */ 060public class DBTableDesktopPane extends JDesktopPane implements DSSchemaIFace, 061 DBSelectTableFieldChangedListener, InternalFrameListener { 062 063 protected DBTableJoin mTableJoins = new DBTableJoin(this); 064 protected DSSchemaIFace mSchema = null; 065 protected Vector mTables = new Vector(); 066 protected TableModelListener mTableModelListener = null; 067 068 private int mJifX = 0; 069 070 /** 071 * DBTableDesktopPane Constructor 072 */ 073 public DBTableDesktopPane() { 074 setDoubleBuffered(true); 075 076 MouseListener mouseListener = new MouseAdapter() { 077 public void mousePressed(MouseEvent ev) { 078 mTableJoins.selectLink(ev); 079 } 080 }; 081 addMouseListener(mouseListener); 082 } 083 084 /** 085 * Finalize/Cleanup 086 */ 087 public void finalize() { 088 mTableModelListener = null; 089 } 090 091 /** 092 * Sets a single listener of TableModel Changes 093 * 094 * @param aL 095 * the listener 096 */ 097 public void setTableModelListener(TableModelListener aL) { 098 mTableModelListener = aL; 099 } 100 101 /** 102 * Returns the TableJoin Object 103 * 104 * @return a joing object 105 */ 106 public DBTableJoin getTableJoins() { 107 return mTableJoins; 108 } 109 110 /** 111 * Sets the Data Src Schema Object and creates all the tables for it 112 * 113 * @param aSchemaDef 114 * the schema 115 */ 116 public void setSchema(DSSchemaIFace aSchemaDef) { 117 mSchema = aSchemaDef; 118 createSchemaTables(mSchema); 119 } 120 121 /** 122 * Returns the Schema Object 123 * 124 * @return schema object 125 */ 126 public DSSchemaIFace getSchema() { 127 return mSchema; 128 } 129 130 /** 131 * Return the appropriate DBTableField from the a desktoppane table frame by 132 * its Id (or table name if the id is -1, and then the field name 133 * 134 * @param aItem 135 * the item to have its field looked up 136 * @return the field in the table frame 137 */ 138 public DBTableField getFieldById(DBSelectTableModelItem aItem) { 139 for (Enumeration et = mTables.elements(); et.hasMoreElements();) { 140 DBTableFrame tblFrame = (DBTableFrame) et.nextElement(); 141 int id = aItem.getTableId(); 142 if ((id != -1 && tblFrame.getId() == id) 143 || (id == -1 && aItem.getTableName().equals( 144 tblFrame.getName()))) { 145 return (DBTableField) DBUIUtils.getFieldByName(tblFrame, aItem 146 .getName()); 147 } 148 } 149 return null; 150 } 151 152 /** 153 * Creates a table frame for each table in the schema 154 * 155 * @param aSchemaDef 156 * the schema 157 */ 158 protected void createSchemaTables(DSSchemaIFace aSchemaDef) { 159 // Remove all current table frames here 160 clearTables(); 161 162 if (mSchema != null) { 163 // Create a table for each one in the schema 164 int id = 0; 165 for (Enumeration et = mSchema.getTables().elements(); et 166 .hasMoreElements();) { 167 createTable((DSTableIFace) et.nextElement(), id++, -1, -1); 168 } 169 } 170 } 171 172 /** 173 * Deletes and adds all the necessary frames 174 */ 175 public void clearTables() { 176 // Remove all current table frames here 177 for (Enumeration et = mTables.elements(); et.hasMoreElements();) { 178 this.remove((DBTableFrame) et.nextElement()); 179 } 180 mTables.clear(); 181 mJifX = 0; 182 } 183 184 /** 185 * Creates a single table frame from the table schema 186 * 187 * @param aTableDef 188 * the table schema 189 * @param aId 190 * the unique id of the table 191 * @param aX 192 * the x coord of the table's location in the builder 193 * @param aY 194 * the y coord of the table's location in the builder 195 */ 196 protected void createTable(DSTableIFace aTableDef, int aId, int aX, int aY) { 197 if (aTableDef == null) 198 return; 199 200 if (aId == -1) { 201 aId = this.getNewId(); 202 } 203 204 // Create a table frame 205 int windowCount = this 206 .getComponentCountInLayer(JDesktopPane.DEFAULT_LAYER.intValue()); 207 int width = 100; 208 209 DBTableFrame jif = new DBTableFrame(aTableDef, aId); 210 jif.setClosable(true); 211 jif.addInternalFrameListener(this); 212 jif.setJoins(mTableJoins); 213 214 add(jif, JDesktopPane.DEFAULT_LAYER); 215 216 Dimension dim = jif.getPreferredSize(); 217 218 // make sure when it is added that it is always visible 219 int panelWidth = getLayeredPaneAbove(jif).getBounds().width; 220 int panelHeight = getLayeredPaneAbove(jif).getBounds().height; 221 if (panelWidth > 0 && mJifX > panelWidth) 222 mJifX = 0; 223 224 // this might not make it visible in the "y" direction 225 // but it will atleast be placed on the canvas 226 int yCoord = 20 * (windowCount % 10); 227 // if (panelHeight > 0 && (yCoord+dim.height) > panelHeight) 228 // yCoord = 0; 229 230 if (aX > -1 && aY > -1) { 231 jif.setBounds(aX, aY, dim.width, dim.height); 232 } else { 233 jif.setBounds(mJifX, yCoord, dim.width, dim.height); 234 } 235 236 mJifX += dim.width + 20; 237 238 // Set this internal frame to be selected 239 240 try { 241 jif.setSelected(true); 242 } catch (java.beans.PropertyVetoException e2) { 243 } 244 245 jif.show(); 246 mTables.add(jif); 247 248 KeyListener keyListener = new KeyAdapter() { 249 public void keyPressed(KeyEvent e) { 250 if (e.getKeyCode() == KeyEvent.VK_DELETE) { 251 if (mTableJoins.removeSelectedLink()) { 252 mTableModelListener.tableChanged(null); 253 e.consume(); 254 } 255 } 256 } 257 }; 258 jif.getList().addKeyListener(keyListener); 259 jif.setTableModelListener(mTableModelListener); 260 } 261 262 /** 263 * Returns a unique and unused id for a new table 264 * 265 * @return a unique (unused) id 266 */ 267 private int getNewId() { 268 Hashtable hash = new Hashtable(); 269 for (Enumeration et = mTables.elements(); et.hasMoreElements();) { 270 String idStr = Integer.toString(((DBTableFrame) et.nextElement()) 271 .getId()); 272 hash.put(idStr, idStr); 273 } 274 275 for (int i = 0; i < Integer.MAX_VALUE; i++) { 276 if (hash.get(Integer.toString(i)) == null) { 277 return i; 278 } 279 } 280 return -1; 281 } 282 283 /** 284 * Adds a new table by name to the workspace, this method looks up the table 285 * schema and adds it 286 * 287 * @param aTableName 288 * the tables name 289 */ 290 public void addTableToWorkspace(String aTableName) { 291 createTable(DBUIUtils.getTableByName(mSchema, aTableName), getNewId(), 292 -1, -1); 293 if (mTableModelListener != null) 294 mTableModelListener.tableChanged(null); 295 } 296 297 /** 298 * Adds a new table by name to the workspace with a DBQueryDefTable object 299 * 300 * @param aTable 301 * the table object 302 */ 303 public void addTableToWorkspace(DBQueryDefTable aTable) { 304 createTable(DBUIUtils.getTableByName(mSchema, aTable.getName()), aTable 305 .getId(), aTable.getPnt().x, aTable.getPnt().y); 306 if (mTableModelListener != null) 307 mTableModelListener.tableChanged(null); 308 } 309 310 /** 311 * Returns the preferred size of the desktop pane so it is large enough for 312 * all the tables (meaning we want to be able to scroll and see all the 313 * tables and not have them clipped) 314 * 315 * @return the dimension 316 */ 317 public Dimension getPreferredSize() { 318 int maxWidth = 0; 319 int maxHeight = 0; 320 Component[] components = getComponents(); 321 for (int i = 0; i < components.length; i++) { 322 Rectangle rect = components[i].getBounds(); 323 maxWidth = Math.max(rect.x + rect.width, maxWidth); 324 maxHeight = Math.max(rect.y + rect.height, maxHeight); 325 } 326 return new Dimension(maxWidth, maxHeight); 327 } 328 329 /** 330 * Overrides paintChildren to make sure all the "joins" get painted 331 */ 332 public void paintChildren(Graphics g) { 333 mTableJoins.paint(g); 334 super.paintChildren(g); 335 } 336 337 /** 338 * Overrides paint so it can "dirty" everything 339 */ 340 public void repaint(long tm, int x, int y, int width, int height) { 341 Rectangle paintRect = new Rectangle(x, y, width, height); 342 Component[] components = getComponents(); 343 for (int i = 0; i < components.length; i++) { 344 Rectangle rect = components[i].getBounds(); 345 if (paintRect.intersects(rect)) { 346 RepaintManager mgr = RepaintManager 347 .currentManager(components[i]); 348 mgr.addDirtyRegion((JComponent) components[i], rect.x, rect.y, 349 rect.width, rect.height); 350 /* 351 * Component[] children = 352 * ((Container)components[i]).getComponents(); for (int 353 * j=0;j<children.length;j++) { Rectangle childRect = 354 * children[j].getBounds(); RepaintManager childMgr = 355 * RepaintManager.currentManager(children[j]); 356 * mgr.addDirtyRegion((JComponent)children[j], childRect.x, 357 * childRect.y, childRect.width, childRect.height); } 358 */ 359 } 360 } 361 362 super.repaint(tm, x, y, width, height); 363 364 } 365 366 /** 367 * Makes sure the entire "panel" will be redrawn by marking the entire 368 * bounds "dirty" 369 */ 370 protected void dirtyAll() { 371 Rectangle rect = getBounds(); 372 RepaintManager mgr = RepaintManager.currentManager(this); 373 mgr.addDirtyRegion((JComponent) this, rect.x, rect.y, rect.width, 374 rect.height); 375 SwingUtilities.invokeLater(new Runnable() { 376 public void run() { 377 repaint(); 378 } 379 }); 380 381 } 382 383 /** 384 * Makes sure the entire "panel" will be redrawn 385 * 386 */ 387 public void makeDirty() { 388 SwingUtilities.invokeLater(new Runnable() { 389 public void run() { 390 dirtyAll(); 391 } 392 }); 393 } 394 395 // -------------------------------------------------------------- 396 // ------------ DSSchemaIFace ----------------- 397 // -------------------------------------------------------------- 398 399 /** 400 * Returns the Vector of TableFrame Objects 401 * 402 * @return vector 403 */ 404 public Vector getTables() { 405 return mTables; 406 } 407 408 /** 409 * Returns the name of the schema 410 * 411 * @return string 412 */ 413 public String getName() { 414 return mSchema != null ? mSchema.getName() : ""; 415 } 416 417 // -------------------------------------------------------------- 418 // ------- DBSelectTableFieldChangedListener Methods ------------ 419 // -------------------------------------------------------------- 420 /** 421 * Makes everything "dirty" and forces an update. 422 */ 423 public void notifyFieldChanged() { 424 makeDirty(); 425 } 426 427 // ----------------------------------------------- 428 // ---------- InternalFrameListener -------------- 429 // ----------------------------------------------- 430 /** 431 * stubbed 432 */ 433 public void internalFrameActivated(InternalFrameEvent e) { 434 } 435 436 /** 437 * Recieces notification that a table frame was closed. It removes all the 438 * joins to and from the table. 439 * 440 * @param e 441 * the event 442 */ 443 public void internalFrameClosed(InternalFrameEvent e) { 444 // Remove it from our taable list 445 DBTableFrame tableFrame = (DBTableFrame) e.getInternalFrame(); 446 mTables.remove(tableFrame); 447 448 // Remove any joins to and from the table 449 mTableJoins.removeTable(tableFrame.getId(), tableFrame.getName()); 450 repaint(); 451 452 if (mTableModelListener != null) 453 mTableModelListener.tableChanged(null); 454 } 455 456 /** 457 * stubbed 458 */ 459 public void internalFrameClosing(InternalFrameEvent e) { 460 } 461 462 /** 463 * stubbed 464 */ 465 public void internalFrameDeactivated(InternalFrameEvent e) { 466 } 467 468 /** 469 * stubbed 470 */ 471 public void internalFrameDeiconified(InternalFrameEvent e) { 472 } 473 474 /** 475 * stubbed 476 */ 477 public void internalFrameIconified(InternalFrameEvent e) { 478 } 479 480 /** 481 * stubbed 482 */ 483 public void internalFrameOpened(InternalFrameEvent e) { 484 } 485 486}