~ubuntu-branches/ubuntu/oneiric/sweethome3d/oneiric-201108050311

« back to all changes in this revision

Viewing changes to src/com/eteks/sweethome3d/swing/HomeComponent3D.java

  • Committer: Bazaar Package Importer
  • Author(s): Gabriele Giacone
  • Date: 2010-05-29 13:17:46 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100529131746-mix5l902gjywddob
Tags: 2.4+dfsg-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
84
84
import javax.media.j3d.J3DGraphics2D;
85
85
import javax.media.j3d.Light;
86
86
import javax.media.j3d.Node;
 
87
import javax.media.j3d.OrderedGroup;
87
88
import javax.media.j3d.Shape3D;
88
89
import javax.media.j3d.Texture;
89
90
import javax.media.j3d.Transform3D;
99
100
import javax.swing.JButton;
100
101
import javax.swing.JComponent;
101
102
import javax.swing.JPanel;
 
103
import javax.swing.JPopupMenu;
102
104
import javax.swing.KeyStroke;
103
105
import javax.swing.RepaintManager;
104
106
import javax.swing.SwingUtilities;
242
244
        }
243
245
        
244
246
        public void canvas3DPostRendered(Canvas3D canvas3D) {
 
247
          // Copy reference to navigation panel image to avoid concurrency problems 
 
248
          // if it's modified in the EDT while this method draws it
 
249
          BufferedImage navigationPanelImage = HomeComponent3D.this.navigationPanelImage;
245
250
          // Render navigation panel upon canvas 3D if it exists
246
251
          if (navigationPanelImage != null) {
247
252
            J3DGraphics2D g2D = canvas3D.getGraphics2D();
520
525
      imageSize.add(componentBounds.x + componentBounds.width, 
521
526
          componentBounds.y + componentBounds.height);
522
527
      if (!imageSize.isEmpty()) {
 
528
        BufferedImage updatedImage = this.navigationPanelImage;
 
529
        // Consider that no navigation panel image is available 
 
530
        // while it's updated
 
531
        this.navigationPanelImage = null;        
523
532
        Graphics2D g2D;
524
 
        if (this.navigationPanelImage == null
525
 
            || this.navigationPanelImage.getWidth() != imageSize.width
526
 
            || this.navigationPanelImage.getHeight() != imageSize.height) {
527
 
          this.navigationPanelImage = new BufferedImage(
 
533
        if (updatedImage == null
 
534
            || updatedImage.getWidth() != imageSize.width
 
535
            || updatedImage.getHeight() != imageSize.height) {
 
536
          updatedImage = new BufferedImage(
528
537
              imageSize.width, imageSize.height, BufferedImage.TYPE_INT_ARGB);
529
 
          g2D = (Graphics2D)this.navigationPanelImage.getGraphics();
 
538
          g2D = (Graphics2D)updatedImage.getGraphics();
530
539
        } else {
531
540
          // Clear image
532
 
          g2D = (Graphics2D)this.navigationPanelImage.getGraphics();
 
541
          g2D = (Graphics2D)updatedImage.getGraphics();
533
542
          Composite oldComposite = g2D.getComposite();
534
543
          g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0));
535
544
          g2D.fill(new Rectangle2D.Double(0, 0, imageSize.width, imageSize.height));
537
546
        }
538
547
        this.navigationPanel.paintAll(g2D);
539
548
        g2D.dispose();
 
549
        // Navigation panel image ready to be displayed
 
550
        this.navigationPanelImage = updatedImage;
540
551
        return;
541
552
      }
542
553
    }
900
911
        public void mouseReleased(MouseEvent ev) {
901
912
          if (!retargetMouseEventToNavigationPanelChildren(ev)) {
902
913
            if (ev.isPopupTrigger()) {
903
 
              getComponentPopupMenu().show(HomeComponent3D.this, ev.getX(), ev.getY());
 
914
              JPopupMenu componentPopupMenu = getComponentPopupMenu();
 
915
              if (componentPopupMenu != null) {
 
916
                componentPopupMenu.show(HomeComponent3D.this, ev.getX(), ev.getY());
 
917
              }
904
918
            }
905
919
          }
906
920
        }
1165
1179
    BranchGroup root = new BranchGroup();
1166
1180
 
1167
1181
    // Build scene tree
1168
 
    root.addChild(createHomeTree(displayShadowOnFloor, listenToHomeUpdates, waitForLoading));
1169
1182
    root.addChild(createBackgroundNode(listenToHomeUpdates));
1170
 
    root.addChild(createGroundNode(-1E5f / 2, -1E5f / 2, 1E5f, 1E5f, listenToHomeUpdates, waitForLoading));
 
1183
    
 
1184
    Group groundAndRoomsGroup = createExtensibleGroup(true);
 
1185
    // Add first ground then home rooms to an ordered group to ensure ground is always drawn behind floors   
 
1186
    groundAndRoomsGroup.addChild(createGroundNode(-1E5f / 2, -1E5f / 2, 1E5f, 1E5f, listenToHomeUpdates, waitForLoading));
 
1187
    for (Room room : this.home.getRooms()) {
 
1188
      addObject(groundAndRoomsGroup, room, waitForLoading);
 
1189
    }    
 
1190
    root.addChild(groundAndRoomsGroup);
 
1191
    
 
1192
    Group wallsAndFurnitureGroup = createExtensibleGroup(false);
 
1193
    // Add walls and pieces already available in a normal group 
 
1194
    // (transparent shapes don't work well in ordered groups) 
 
1195
    for (Wall wall : this.home.getWalls()) {
 
1196
      addObject(wallsAndFurnitureGroup, wall, waitForLoading);
 
1197
    }
 
1198
    for (HomePieceOfFurniture piece : this.home.getFurniture()) {
 
1199
      addObject(wallsAndFurnitureGroup, piece, waitForLoading);
 
1200
    }
 
1201
    if (displayShadowOnFloor) {
 
1202
      addShadowOnFloor(groundAndRoomsGroup);
 
1203
    }
 
1204
    root.addChild(wallsAndFurnitureGroup);
 
1205
    
 
1206
    // Add default lights
1171
1207
    for (Light light : createLights(listenToHomeUpdates)) {
1172
1208
      root.addChild(light);
1173
1209
    }
 
1210
    
 
1211
    if (listenToHomeUpdates) {
 
1212
      // Add wall, furniture, room listeners to home for further update    
 
1213
      addWallListener(wallsAndFurnitureGroup);
 
1214
      addFurnitureListener(wallsAndFurnitureGroup);
 
1215
      addRoomListener(groundAndRoomsGroup, 1);
 
1216
      // Add environment listeners
 
1217
      addEnvironmentListeners();
 
1218
      // Should update shadow on floor too but in the facts 
 
1219
      // User Interface doesn't propose to modify the furniture of a home
 
1220
      // that displays shadow on floor yet
 
1221
    }
1174
1222
 
1175
1223
    return root;
1176
1224
  }
1365
1413
                                        (lightColor & 0xFF) / 256f * defaultColor.z));
1366
1414
    clearPrintedImageCache();
1367
1415
  }
1368
 
  
1369
 
  /**
1370
 
   * Returns a <code>home</code> new tree node, with branches for each wall 
1371
 
   * and piece of furniture of <code>home</code>. 
1372
 
   */
1373
 
  private Node createHomeTree(boolean displayShadowOnFloor, 
1374
 
                              boolean listenToHomeUpdates, 
1375
 
                              boolean waitForLoading) {
1376
 
    Group homeRoot = createHomeRoot();
1377
 
    // Add walls, pieces and rooms already available 
1378
 
    for (Wall wall : this.home.getWalls()) {
1379
 
      addObject(homeRoot, wall, waitForLoading);
1380
 
    }
1381
 
    for (HomePieceOfFurniture piece : this.home.getFurniture()) {
1382
 
      addObject(homeRoot, piece, waitForLoading);
1383
 
    }
1384
 
    for (Room room : this.home.getRooms()) {
1385
 
      addObject(homeRoot, room, waitForLoading);
1386
 
    }    
1387
 
    
1388
 
    if (displayShadowOnFloor) {
1389
 
      addShadowOnFloor(homeRoot);
1390
 
    }
1391
 
    
1392
 
    if (listenToHomeUpdates) {
1393
 
      // Add wall, furniture, room listeners to home for further update    
1394
 
      addWallListener(homeRoot);
1395
 
      addFurnitureListener(homeRoot);
1396
 
      addRoomListener(homeRoot);
1397
 
      // Add environment listeners
1398
 
      addEnvironmentListeners();
1399
 
      // Should update shadow on floor too but in the facts 
1400
 
      // User Interface doesn't propose to modify the furniture of a home
1401
 
      // that displays shadow on floor yet
1402
 
    }
1403
 
    return homeRoot;
1404
 
  }
1405
 
 
1406
 
  /**
1407
 
   * Returns a new group at home subtree root.
1408
 
   */
1409
 
  private Group createHomeRoot() {
1410
 
    Group homeGroup = new Group();    
 
1416
  /**
 
1417
   * Returns a new extensible group.  
 
1418
   */
 
1419
  private Group createExtensibleGroup(boolean ordered) {
 
1420
    Group homeGroup = ordered
 
1421
        ? new OrderedGroup()
 
1422
        : new Group();    
1411
1423
    //  Allow group to have new children
1412
1424
    homeGroup.setCapability(Group.ALLOW_CHILDREN_WRITE);
1413
1425
    homeGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
1415
1427
  }
1416
1428
 
1417
1429
  /**
1418
 
   * Adds a wall listener to home walls  
1419
 
   * that updates the scene <code>homeRoot</code>, each time a wall is added, updated or deleted. 
 
1430
   * Adds a wall listener to home walls that updates the children of the given 
 
1431
   * <code>group</code>, each time a wall is added, updated or deleted. 
1420
1432
   */
1421
 
  private void addWallListener(final Group homeRoot) {
 
1433
  private void addWallListener(final Group group) {
1422
1434
    this.wallChangeListener = new PropertyChangeListener() {
1423
1435
        public void propertyChange(PropertyChangeEvent ev) {
1424
1436
          updateWall((Wall)ev.getSource());          
1433
1445
          Wall wall = ev.getItem();
1434
1446
          switch (ev.getType()) {
1435
1447
            case ADD :
1436
 
              addObject(homeRoot, wall, false);
 
1448
              addObject(group, wall, false);
1437
1449
              wall.addPropertyChangeListener(wallChangeListener);
1438
1450
              break;
1439
1451
            case DELETE :
1448
1460
  }
1449
1461
 
1450
1462
  /**
1451
 
   * Adds a furniture listener to home that updates the scene <code>homeRoot</code>, 
 
1463
   * Adds a furniture listener to home that updates the children of the given <code>group</code>, 
1452
1464
   * each time a piece of furniture is added, updated or deleted. 
1453
1465
   */
1454
 
  private void addFurnitureListener(final Group homeRoot) {
 
1466
  private void addFurnitureListener(final Group group) {
1455
1467
    this.furnitureChangeListener = new PropertyChangeListener() {
1456
1468
        public void propertyChange(PropertyChangeEvent ev) {
1457
 
          switch (HomePieceOfFurniture.Property.valueOf(ev.getPropertyName())) {
1458
 
            case X:
1459
 
            case Y:
1460
 
            case ANGLE:
1461
 
            case WIDTH:
1462
 
            case DEPTH:
1463
 
            case HEIGHT:
1464
 
            case ELEVATION:
1465
 
            case COLOR:
1466
 
            case TEXTURE:
1467
 
            case MODEL_MIRRORED:
1468
 
            case VISIBLE:
 
1469
        if (HomePieceOfFurniture.Property.X.name().equals(ev.getPropertyName())
 
1470
            || HomePieceOfFurniture.Property.X.name().equals(ev.getPropertyName())
 
1471
            || HomePieceOfFurniture.Property.Y.name().equals(ev.getPropertyName())
 
1472
            || HomePieceOfFurniture.Property.ANGLE.name().equals(ev.getPropertyName())
 
1473
            || HomePieceOfFurniture.Property.WIDTH.name().equals(ev.getPropertyName())
 
1474
            || HomePieceOfFurniture.Property.DEPTH.name().equals(ev.getPropertyName())
 
1475
            || HomePieceOfFurniture.Property.HEIGHT.name().equals(ev.getPropertyName())
 
1476
            || HomePieceOfFurniture.Property.ELEVATION.name().equals(ev.getPropertyName())
 
1477
            || HomePieceOfFurniture.Property.COLOR.name().equals(ev.getPropertyName())
 
1478
            || HomePieceOfFurniture.Property.TEXTURE.name().equals(ev.getPropertyName())
 
1479
            || HomePieceOfFurniture.Property.MODEL_MIRRORED.name().equals(ev.getPropertyName())
 
1480
            || HomePieceOfFurniture.Property.VISIBLE.name().equals(ev.getPropertyName())) {
1469
1481
              HomePieceOfFurniture piece = (HomePieceOfFurniture)ev.getSource();
1470
1482
              updateObjects(Arrays.asList(new HomePieceOfFurniture [] {piece}));
1471
1483
              // If piece is or contains a door or a window, update walls that intersect with piece
1472
1484
              if (containsDoorsAndWindows(piece)) {
1473
1485
                updateObjects(home.getWalls());
1474
1486
              }
1475
 
              break;
1476
1487
          }
1477
1488
        }
1478
1489
      };
1484
1495
          HomePieceOfFurniture piece = (HomePieceOfFurniture)ev.getItem();
1485
1496
          switch (ev.getType()) {
1486
1497
            case ADD :
1487
 
              addObject(homeRoot, piece, false);
 
1498
              addObject(group, piece, false);
1488
1499
              piece.addPropertyChangeListener(furnitureChangeListener);
1489
1500
              break;
1490
1501
            case DELETE :
1518
1529
  }
1519
1530
  
1520
1531
  /**
1521
 
   * Adds a room listener to home rooms that updates the scene 
1522
 
   * <code>homeRoot</code>, each time a room is added, updated or deleted. 
 
1532
   * Adds a room listener to home rooms that updates the children of the given 
 
1533
   * <code>group</code>, each time a room is added, updated or deleted. 
1523
1534
   */
1524
 
  private void addRoomListener(final Group homeRoot) {
 
1535
  private void addRoomListener(final Group group, final int indexOffset) {
1525
1536
    this.roomChangeListener = new PropertyChangeListener() {
1526
1537
        public void propertyChange(PropertyChangeEvent ev) {
1527
1538
          updateObjects(Arrays.asList(new Room [] {(Room)ev.getSource()}));
1536
1547
          Room room = ev.getItem();
1537
1548
          switch (ev.getType()) {
1538
1549
            case ADD :
1539
 
              addObject(homeRoot, room, false);
 
1550
              // Add room to its group at the index indicated by the event 
 
1551
              // to ensure the 3D rooms are drawn in the same order as in the plan  
 
1552
              addObject(group, room, ev.getIndex() + indexOffset, false);
1540
1553
              room.addPropertyChangeListener(roomChangeListener);
1541
1554
              break;
1542
1555
            case DELETE :
1573
1586
  }
1574
1587
 
1575
1588
  /**
1576
 
   * Adds to <code>homeRoot</code> a wall branch matching <code>wall</code>.
1577
 
   */
1578
 
  private void addObject(Group homeRoot, Selectable homeObject, boolean waitForLoading) {
 
1589
   * Adds to <code>group</code> a branch matching <code>homeObject</code>.
 
1590
   */
 
1591
  private void addObject(Group group, Selectable homeObject, boolean waitForLoading) {
 
1592
    addObject(group, homeObject, -1, waitForLoading);
 
1593
  }
 
1594
 
 
1595
  /**
 
1596
   * Adds to <code>group</code> a branch matching <code>homeObject</code> at a given <code>index</code>.
 
1597
   * If <code>index</code> is equal to -1, <code>homeObject</code> will be added at the end of the group.
 
1598
   */
 
1599
  private void addObject(Group group, Selectable homeObject, int index, boolean waitForLoading) {
1579
1600
    Object3DBranch object3D = createObject3D(homeObject, waitForLoading);
1580
1601
    this.homeObjects.put(homeObject, object3D);
1581
 
    homeRoot.addChild(object3D);
 
1602
    if (index == -1) {
 
1603
      group.addChild(object3D);
 
1604
    } else {
 
1605
      group.insertChild(object3D, index);
 
1606
    }
1582
1607
    clearPrintedImageCache();
1583
1608
  }
1584
1609