1 19 20 package org.netbeans.swing.outline; 21 22 import java.awt.Font ; 23 import java.awt.FontMetrics ; 24 import java.awt.Graphics ; 25 import java.awt.Insets ; 26 import java.awt.Rectangle ; 27 import java.awt.event.ActionEvent ; 28 import java.awt.event.ActionListener ; 29 import java.awt.event.ComponentAdapter ; 30 import java.awt.event.ComponentEvent ; 31 import java.awt.event.ComponentListener ; 32 import java.awt.event.MouseEvent ; 33 import java.util.ArrayList ; 34 import java.util.EventObject ; 35 import java.util.List ; 36 import javax.swing.JScrollBar ; 37 import javax.swing.JScrollPane ; 38 import javax.swing.JTable ; 39 import javax.swing.JTree ; 40 import javax.swing.JViewport ; 41 import javax.swing.ListSelectionModel ; 42 import javax.swing.Timer ; 43 import javax.swing.UIManager ; 44 import javax.swing.event.TableModelEvent ; 45 import javax.swing.event.TreeModelEvent ; 46 import javax.swing.table.TableCellRenderer ; 47 import javax.swing.table.TableModel ; 48 import javax.swing.tree.AbstractLayoutCache ; 49 import javax.swing.tree.TreePath ; 50 51 162 public final class Outline extends JTable { 163 166 private boolean initialized = false; 167 private Boolean cachedRootVisible = null; 168 private RenderDataProvider renderDataProvider = null; 169 private ComponentListener componentListener = null; 170 171 public Outline() { 172 init(); 173 } 174 175 public Outline(OutlineModel mdl) { 176 super (mdl); 177 init(); 178 } 179 180 private void init() { 181 initialized = true; 182 setDefaultRenderer(Object .class, new DefaultOutlineCellRenderer()); 183 } 184 185 186 public TableCellRenderer getCellRenderer(int row, int column) { 187 TableCellRenderer result; 188 if (column == 0) { 189 result = getDefaultRenderer(Object .class); 190 } else { 191 result = super.getCellRenderer(row, column); 192 } 193 return result; 194 } 195 196 200 public RenderDataProvider getRenderDataProvider() { 201 return renderDataProvider; 202 } 203 204 209 public void setRenderDataProvider (RenderDataProvider provider) { 210 if (provider != renderDataProvider) { 211 RenderDataProvider old = renderDataProvider; 212 renderDataProvider = provider; 213 firePropertyChange ("renderDataProvider", old, provider); } 215 } 216 217 219 TreePathSupport getTreePathSupport () { 220 OutlineModel mdl = getOutlineModel(); 221 if (mdl != null) { 222 return mdl.getTreePathSupport(); 223 } else { 224 return null; 225 } 226 } 227 228 234 AbstractLayoutCache getLayoutCache () { 235 OutlineModel mdl = getOutlineModel(); 236 if (mdl != null) { 237 return mdl.getLayout(); 238 } else { 239 return null; 240 } 241 } 242 243 boolean isTreeColumnIndex (int column) { 244 return column == 0; 246 } 247 248 public boolean isVisible (TreePath path) { 249 if (getTreePathSupport() != null) { 250 return getTreePathSupport().isVisible(path); 251 } 252 return false; 253 } 254 255 256 public void setRowHeight(int val) { 257 super.setRowHeight(val); 258 if (getLayoutCache() != null) { 259 getLayoutCache().setRowHeight(val); 260 } 261 } 262 263 264 public void setRootVisible (boolean val) { 265 if (getOutlineModel() == null) { 266 cachedRootVisible = val ? Boolean.TRUE : Boolean.FALSE; 267 } 268 if (val != isRootVisible()) { 269 getLayoutCache().setRootVisible(val); 272 firePropertyChange("rootVisible", !val, val); } 274 } 275 276 277 public boolean isRootVisible() { 278 if (getLayoutCache() == null) { 279 return cachedRootVisible != null ? 280 cachedRootVisible.booleanValue() : true; 281 } else { 282 return getLayoutCache().isRootVisible(); 283 } 284 } 285 286 289 public void setModel (TableModel mdl) { 290 if (initialized && (!(mdl instanceof OutlineModel))) { 291 throw new IllegalArgumentException ( 292 "Table model for an Outline must be an instance of " + 293 "OutlineModel"); } 295 if (mdl instanceof OutlineModel) { 296 AbstractLayoutCache layout = ((OutlineModel) mdl).getLayout(); 297 if (cachedRootVisible != null) { 298 299 layout.setRootVisible( 300 cachedRootVisible.booleanValue()); 301 302 } 303 304 layout.setRowHeight(getRowHeight()); 305 306 if (((OutlineModel) mdl).isLargeModel()) { 307 addComponentListener (getComponentListener()); 308 layout.setNodeDimensions(new ND()); 309 } else { 310 if (componentListener != null) { 311 removeComponentListener (componentListener); 312 componentListener = null; 313 } 314 } 315 } 316 317 super.setModel(mdl); 318 } 319 320 322 public OutlineModel getOutlineModel() { 323 TableModel mdl = getModel(); 324 if (mdl instanceof OutlineModel) { 325 return (OutlineModel) getModel(); 326 } else { 327 return null; 328 } 329 } 330 331 332 public void expandPath (TreePath path) { 333 getTreePathSupport().expandPath (path); 334 } 335 336 public void collapsePath (TreePath path) { 337 getTreePathSupport().collapsePath (path); 338 } 339 340 public Rectangle getPathBounds(TreePath path) { 341 Insets i = getInsets(); 342 Rectangle bounds = getLayoutCache().getBounds(path, null); 343 344 if(bounds != null && i != null) { 345 bounds.x += i.left; 346 bounds.y += i.top; 347 } 348 return bounds; 349 } 350 351 public TreePath getClosestPathForLocation(int x, int y) { 352 Insets i = getInsets(); 353 if (i != null) { 354 return getLayoutCache().getPathClosestTo(x - i.left, y - i.top); 355 } else { 356 return getLayoutCache().getPathClosestTo(x,y); 357 } 358 } 359 360 public boolean editCellAt (int row, int column, EventObject e) { 361 if (isTreeColumnIndex (column) && e instanceof MouseEvent ) { 364 MouseEvent me = (MouseEvent ) e; 365 TreePath path = getLayoutCache().getPathClosestTo(me.getX(), me.getY()); 366 if (!getOutlineModel().isLeaf(path.getLastPathComponent())) { 367 int handleWidth = DefaultOutlineCellRenderer.getExpansionHandleWidth(); 368 Insets ins = getInsets(); 369 int handleStart = ins.left + ((path.getPathCount() - 1) * DefaultOutlineCellRenderer.getNestingWidth()); 370 int handleEnd = ins.left + handleStart + handleWidth; 371 372 374 if ((me.getX() > ins.left && me.getX() >= handleStart && me.getX() <= handleEnd) || 375 me.getClickCount() > 1) { 376 377 boolean expanded = getLayoutCache().isExpanded(path); 378 if (!expanded) { 379 getTreePathSupport().expandPath(path); 380 } else { 381 getTreePathSupport().collapsePath(path); 382 } 383 return false; 384 } 385 } 386 } 387 388 return super.editCellAt(row, column, e); 389 } 390 391 private boolean needCalcRowHeight = true; 392 395 private void calcRowHeight(Graphics g) { 396 Integer i = (Integer ) UIManager.get("netbeans.outline.rowHeight"); 399 int rowHeight; 400 if (i != null) { 401 rowHeight = i.intValue(); 402 } else { 403 Font f = getFont(); 405 FontMetrics fm = g.getFontMetrics(f); 406 rowHeight = Math.max(fm.getHeight()+3, 407 DefaultOutlineCellRenderer.getExpansionHandleHeight()); 408 } 409 needCalcRowHeight = false; 411 setRowHeight(rowHeight); 414 } 415 416 public void tableChanged(TableModelEvent e) { 417 super.tableChanged(e); 419 } 421 422 public void paint(Graphics g) { 423 if (needCalcRowHeight) { 424 calcRowHeight(g); 425 return; 427 } 428 super.paint(g); 429 } 430 431 433 private ComponentListener getComponentListener() { 434 if (componentListener == null) { 435 componentListener = new SizeManager(); 436 } 437 return componentListener; 438 } 439 440 private JScrollPane getScrollPane() { 441 JScrollPane result = null; 442 if (getParent() instanceof JViewport ) { 443 if (((JViewport ) getParent()).getParent() instanceof JScrollPane ) { 444 result = (JScrollPane ) ((JViewport ) getParent()).getParent(); 445 } 446 } 447 return result; 448 } 449 450 private void change() { 451 revalidate(); 452 repaint(); 453 } 454 455 private class ND extends AbstractLayoutCache.NodeDimensions { 456 457 public Rectangle getNodeDimensions(Object value, int row, int depth, 458 boolean expanded, Rectangle bounds) { 459 460 int wid = Outline.this.getColumnModel().getColumn(0).getPreferredWidth(); 461 bounds.setBounds (0, row * getRowHeight(), wid, getRowHeight()); 462 return bounds; 463 } 464 465 } 466 467 468 471 private class SizeManager extends ComponentAdapter implements ActionListener { 472 protected Timer timer = null; 473 protected JScrollBar scrollBar = null; 474 475 public void componentMoved(ComponentEvent e) { 476 if(timer == null) { 477 JScrollPane scrollPane = getScrollPane(); 478 479 if(scrollPane == null) { 480 change(); 481 } else { 482 scrollBar = scrollPane.getVerticalScrollBar(); 483 if(scrollBar == null || 484 !scrollBar.getValueIsAdjusting()) { 485 if((scrollBar = scrollPane.getHorizontalScrollBar()) 487 != null && scrollBar.getValueIsAdjusting()) { 488 489 startTimer(); 490 } else { 491 change(); 492 } 493 } else { 494 startTimer(); 495 } 496 } 497 } 498 } 499 500 protected void startTimer() { 501 if(timer == null) { 502 timer = new Timer (200, this); 503 timer.setRepeats(true); 504 } 505 timer.start(); 506 } 507 508 public void actionPerformed(ActionEvent ae) { 509 if(scrollBar == null || !scrollBar.getValueIsAdjusting()) { 510 if(timer != null) 511 timer.stop(); 512 change(); 513 timer = null; 514 scrollBar = null; 515 } 516 } 517 518 public void componentHidden(ComponentEvent e) { 519 } 520 521 public void componentResized(ComponentEvent e) { 522 } 523 524 public void componentShown(ComponentEvent e) { 525 } 526 } 527 } 528 | Popular Tags |