~ubuntu-branches/ubuntu/utopic/sweethome3d/utopic

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Gabriele Giacone
  • Date: 2013-03-22 23:35:34 UTC
  • mfrom: (1.1.12)
  • Revision ID: package-import@ubuntu.com-20130322233534-k9g9mz1vch0dfy4y
Tags: 4.0+dfsg-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
import java.awt.FontMetrics;
35
35
import java.awt.Graphics;
36
36
import java.awt.Graphics2D;
37
 
import java.awt.GraphicsEnvironment;
38
37
import java.awt.GridBagConstraints;
39
38
import java.awt.GridBagLayout;
40
39
import java.awt.Insets;
214
213
  private enum ActionType {DELETE_SELECTION, ESCAPE, 
215
214
      MOVE_SELECTION_LEFT, MOVE_SELECTION_UP, MOVE_SELECTION_DOWN, MOVE_SELECTION_RIGHT,
216
215
      MOVE_SELECTION_FAST_LEFT, MOVE_SELECTION_FAST_UP, MOVE_SELECTION_FAST_DOWN, MOVE_SELECTION_FAST_RIGHT,
217
 
      TOGGLE_MAGNETISM_ON, TOGGLE_MAGNETISM_OFF, 
218
 
      ACTIVATE_DUPLICATION, DEACTIVATE_DUPLICATION, 
 
216
      TOGGLE_MAGNETISM_ON, TOGGLE_MAGNETISM_OFF,
 
217
      ACTIVATE_ALIGNMENT, DEACTIVATE_ALIGNMENT,
 
218
      ACTIVATE_DUPLICATION, DEACTIVATE_DUPLICATION,       
219
219
      ACTIVATE_EDITIION, DEACTIVATE_EDITIION}
220
220
  
221
221
  private static final float    MARGIN = 40;
581
581
        "resources/cursors/panning32x32.png", "Panning cursor", Cursor.HAND_CURSOR);
582
582
    this.duplicationCursor = DragSource.DefaultCopyDrop;
583
583
    this.patternImagesCache = new HashMap<TextureImage, BufferedImage>();
584
 
    // Install default colors
585
 
    super.setForeground(UIManager.getColor("textText"));
586
 
    super.setBackground(UIManager.getColor("window"));
 
584
    // Install default colors using same colors as a text field
 
585
    super.setForeground(UIManager.getColor("TextField.foreground"));
 
586
    super.setBackground(UIManager.getColor("TextField.background"));
587
587
  }
588
588
 
589
589
  /**
598
598
          if (furnitureTopViewIconsCache != null
599
599
              && (HomePieceOfFurniture.Property.COLOR.name().equals(ev.getPropertyName())
600
600
                  || HomePieceOfFurniture.Property.TEXTURE.name().equals(ev.getPropertyName())
 
601
                  || HomePieceOfFurniture.Property.MODEL_MATERIALS.name().equals(ev.getPropertyName())
601
602
                  || HomePieceOfFurniture.Property.SHININESS.name().equals(ev.getPropertyName())
602
603
                  || (HomePieceOfFurniture.Property.WIDTH.name().equals(ev.getPropertyName())
603
604
                      || HomePieceOfFurniture.Property.DEPTH.name().equals(ev.getPropertyName())
995
996
        if (isEnabled() && !ev.isPopupTrigger()) {
996
997
          requestFocusInWindow();          
997
998
          if (ev.getButton() == MouseEvent.BUTTON1) {
 
999
            boolean alignmentActivated = OperatingSystem.isWindows() || OperatingSystem.isMacOSX() 
 
1000
                ? ev.isShiftDown()
 
1001
                : ev.isShiftDown() && !ev.isAltDown();
 
1002
            boolean duplicationActivated = OperatingSystem.isMacOSX() 
 
1003
                ? ev.isAltDown() 
 
1004
                : ev.isControlDown();
 
1005
            boolean magnetismToggled = OperatingSystem.isWindows() 
 
1006
                ? ev.isAltDown() 
 
1007
                : (OperatingSystem.isMacOSX() 
 
1008
                       ? ev.isMetaDown()
 
1009
                       : ev.isShiftDown() && ev.isAltDown());
998
1010
            controller.pressMouse(convertXPixelToModel(ev.getX()), convertYPixelToModel(ev.getY()), 
999
 
                ev.getClickCount(), ev.isShiftDown(), 
1000
 
                OperatingSystem.isMacOSX() ? ev.isAltDown() : ev.isControlDown());
 
1011
                ev.getClickCount(), ev.isShiftDown() && !ev.isControlDown() && !ev.isAltDown() && !ev.isMetaDown(), 
 
1012
                alignmentActivated, duplicationActivated, magnetismToggled);
1001
1013
          }
1002
1014
        }
1003
1015
      }
1104
1116
    inputMap.put(KeyStroke.getKeyStroke("DELETE"), ActionType.DELETE_SELECTION);
1105
1117
    inputMap.put(KeyStroke.getKeyStroke("BACK_SPACE"), ActionType.DELETE_SELECTION);
1106
1118
    inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), ActionType.ESCAPE);
 
1119
    inputMap.put(KeyStroke.getKeyStroke("shift ESCAPE"), ActionType.ESCAPE);
1107
1120
    inputMap.put(KeyStroke.getKeyStroke("LEFT"), ActionType.MOVE_SELECTION_LEFT);
1108
1121
    inputMap.put(KeyStroke.getKeyStroke("shift LEFT"), ActionType.MOVE_SELECTION_FAST_LEFT);
1109
1122
    inputMap.put(KeyStroke.getKeyStroke("UP"), ActionType.MOVE_SELECTION_UP);
1112
1125
    inputMap.put(KeyStroke.getKeyStroke("shift DOWN"), ActionType.MOVE_SELECTION_FAST_DOWN);
1113
1126
    inputMap.put(KeyStroke.getKeyStroke("RIGHT"), ActionType.MOVE_SELECTION_RIGHT);
1114
1127
    inputMap.put(KeyStroke.getKeyStroke("shift RIGHT"), ActionType.MOVE_SELECTION_FAST_RIGHT);
1115
 
    inputMap.put(KeyStroke.getKeyStroke("shift pressed SHIFT"), ActionType.TOGGLE_MAGNETISM_ON);
1116
 
    inputMap.put(KeyStroke.getKeyStroke("released SHIFT"), ActionType.TOGGLE_MAGNETISM_OFF);
1117
 
    inputMap.put(KeyStroke.getKeyStroke("shift ESCAPE"), ActionType.ESCAPE);
1118
1128
    inputMap.put(KeyStroke.getKeyStroke("ENTER"), ActionType.ACTIVATE_EDITIION);
1119
1129
    inputMap.put(KeyStroke.getKeyStroke("shift ENTER"), ActionType.ACTIVATE_EDITIION);
 
1130
 
1120
1131
    if (OperatingSystem.isMacOSX()) {
1121
1132
      // Under Mac OS X, duplication with Alt key 
1122
1133
      inputMap.put(KeyStroke.getKeyStroke("alt pressed ALT"), ActionType.ACTIVATE_DUPLICATION);
1123
1134
      inputMap.put(KeyStroke.getKeyStroke("released ALT"), ActionType.DEACTIVATE_DUPLICATION);
1124
1135
      inputMap.put(KeyStroke.getKeyStroke("shift alt pressed ALT"), ActionType.ACTIVATE_DUPLICATION);
1125
1136
      inputMap.put(KeyStroke.getKeyStroke("shift released ALT"), ActionType.DEACTIVATE_DUPLICATION);
1126
 
      inputMap.put(KeyStroke.getKeyStroke("alt ESCAPE"), ActionType.ESCAPE);
 
1137
      inputMap.put(KeyStroke.getKeyStroke("meta alt pressed ALT"), ActionType.ACTIVATE_DUPLICATION);
 
1138
      inputMap.put(KeyStroke.getKeyStroke("meta released ALT"), ActionType.DEACTIVATE_DUPLICATION);
 
1139
      inputMap.put(KeyStroke.getKeyStroke("shift meta alt pressed ALT"), ActionType.ACTIVATE_DUPLICATION);
 
1140
      inputMap.put(KeyStroke.getKeyStroke("shift meta released ALT"), ActionType.DEACTIVATE_DUPLICATION);
 
1141
      inputMap.put(KeyStroke.getKeyStroke("alt ESCAPE"), ActionType.ESCAPE);
 
1142
      inputMap.put(KeyStroke.getKeyStroke("alt ENTER"), ActionType.ACTIVATE_EDITIION);
 
1143
    } else {
 
1144
      // Under other systems, duplication with Ctrl key 
 
1145
      inputMap.put(KeyStroke.getKeyStroke("control pressed CONTROL"), ActionType.ACTIVATE_DUPLICATION);
 
1146
      inputMap.put(KeyStroke.getKeyStroke("released CONTROL"), ActionType.DEACTIVATE_DUPLICATION);
 
1147
      inputMap.put(KeyStroke.getKeyStroke("shift control pressed CONTROL"), ActionType.ACTIVATE_DUPLICATION);
 
1148
      inputMap.put(KeyStroke.getKeyStroke("shift released CONTROL"), ActionType.DEACTIVATE_DUPLICATION);
 
1149
      inputMap.put(KeyStroke.getKeyStroke("meta control pressed CONTROL"), ActionType.ACTIVATE_DUPLICATION);
 
1150
      inputMap.put(KeyStroke.getKeyStroke("meta released CONTROL"), ActionType.DEACTIVATE_DUPLICATION);
 
1151
      inputMap.put(KeyStroke.getKeyStroke("shift meta control pressed CONTROL"), ActionType.ACTIVATE_DUPLICATION);
 
1152
      inputMap.put(KeyStroke.getKeyStroke("shift meta released CONTROL"), ActionType.DEACTIVATE_DUPLICATION);
 
1153
      inputMap.put(KeyStroke.getKeyStroke("control ESCAPE"), ActionType.ESCAPE);
 
1154
      inputMap.put(KeyStroke.getKeyStroke("control ENTER"), ActionType.ACTIVATE_EDITIION);
 
1155
    }
 
1156
    
 
1157
    if (OperatingSystem.isWindows()) {
 
1158
      // Under Windows, magnetism toggled with Alt key 
 
1159
      inputMap.put(KeyStroke.getKeyStroke("alt pressed ALT"), ActionType.TOGGLE_MAGNETISM_ON);
 
1160
      inputMap.put(KeyStroke.getKeyStroke("released ALT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1161
      inputMap.put(KeyStroke.getKeyStroke("shift alt pressed ALT"), ActionType.TOGGLE_MAGNETISM_ON);
 
1162
      inputMap.put(KeyStroke.getKeyStroke("shift released ALT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1163
      inputMap.put(KeyStroke.getKeyStroke("control alt pressed ALT"), ActionType.TOGGLE_MAGNETISM_ON);
 
1164
      inputMap.put(KeyStroke.getKeyStroke("control released ALT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1165
      inputMap.put(KeyStroke.getKeyStroke("shift control alt pressed ALT"), ActionType.TOGGLE_MAGNETISM_ON);
 
1166
      inputMap.put(KeyStroke.getKeyStroke("shift control released ALT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1167
      inputMap.put(KeyStroke.getKeyStroke("alt ESCAPE"), ActionType.ESCAPE);
 
1168
      inputMap.put(KeyStroke.getKeyStroke("alt ENTER"), ActionType.ACTIVATE_EDITIION);
 
1169
    } else if (OperatingSystem.isMacOSX()) {
 
1170
      // Under Windows, magnetism toggled with cmd key 
 
1171
      inputMap.put(KeyStroke.getKeyStroke("meta pressed META"), ActionType.TOGGLE_MAGNETISM_ON);
 
1172
      inputMap.put(KeyStroke.getKeyStroke("released META"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1173
      inputMap.put(KeyStroke.getKeyStroke("shift meta pressed META"), ActionType.TOGGLE_MAGNETISM_ON);
 
1174
      inputMap.put(KeyStroke.getKeyStroke("shift released META"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1175
      inputMap.put(KeyStroke.getKeyStroke("alt meta pressed META"), ActionType.TOGGLE_MAGNETISM_ON);
 
1176
      inputMap.put(KeyStroke.getKeyStroke("alt released META"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1177
      inputMap.put(KeyStroke.getKeyStroke("shift alt meta pressed META"), ActionType.TOGGLE_MAGNETISM_ON);
 
1178
      inputMap.put(KeyStroke.getKeyStroke("shift alt released META"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1179
      inputMap.put(KeyStroke.getKeyStroke("meta ESCAPE"), ActionType.ESCAPE);
 
1180
      inputMap.put(KeyStroke.getKeyStroke("meta ENTER"), ActionType.ACTIVATE_EDITIION);
 
1181
    } else {
 
1182
      // Under other Unix systems, magnetism toggled with Alt + Shift key 
 
1183
      inputMap.put(KeyStroke.getKeyStroke("shift alt pressed ALT"), ActionType.TOGGLE_MAGNETISM_ON);
1127
1184
      inputMap.put(KeyStroke.getKeyStroke("alt shift pressed SHIFT"), ActionType.TOGGLE_MAGNETISM_ON);
1128
1185
      inputMap.put(KeyStroke.getKeyStroke("alt released SHIFT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1186
      inputMap.put(KeyStroke.getKeyStroke("control shift alt pressed ALT"), ActionType.TOGGLE_MAGNETISM_ON);
 
1187
      inputMap.put(KeyStroke.getKeyStroke("control alt shift pressed SHIFT"), ActionType.TOGGLE_MAGNETISM_ON);
 
1188
      inputMap.put(KeyStroke.getKeyStroke("control alt released SHIFT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1189
      inputMap.put(KeyStroke.getKeyStroke("alt shift ESCAPE"), ActionType.ESCAPE);
 
1190
      inputMap.put(KeyStroke.getKeyStroke("alt shift  ENTER"), ActionType.ACTIVATE_EDITIION);
 
1191
      inputMap.put(KeyStroke.getKeyStroke("control alt shift ESCAPE"), ActionType.ESCAPE);
 
1192
      inputMap.put(KeyStroke.getKeyStroke("control alt shift  ENTER"), ActionType.ACTIVATE_EDITIION);
 
1193
    }
 
1194
 
 
1195
    inputMap.put(KeyStroke.getKeyStroke("shift pressed SHIFT"), ActionType.ACTIVATE_ALIGNMENT);
 
1196
    inputMap.put(KeyStroke.getKeyStroke("released SHIFT"), ActionType.DEACTIVATE_ALIGNMENT);
 
1197
    if (OperatingSystem.isWindows()) {
 
1198
      inputMap.put(KeyStroke.getKeyStroke("control shift pressed SHIFT"), ActionType.ACTIVATE_ALIGNMENT);
 
1199
      inputMap.put(KeyStroke.getKeyStroke("control released SHIFT"), ActionType.DEACTIVATE_ALIGNMENT);
 
1200
      inputMap.put(KeyStroke.getKeyStroke("alt shift pressed SHIFT"), ActionType.ACTIVATE_ALIGNMENT);
 
1201
      inputMap.put(KeyStroke.getKeyStroke("alt released SHIFT"), ActionType.DEACTIVATE_ALIGNMENT);
 
1202
      
 
1203
    } else if (OperatingSystem.isMacOSX()) {
 
1204
      inputMap.put(KeyStroke.getKeyStroke("alt shift pressed SHIFT"), ActionType.ACTIVATE_ALIGNMENT);
 
1205
      inputMap.put(KeyStroke.getKeyStroke("alt released SHIFT"), ActionType.DEACTIVATE_ALIGNMENT);
 
1206
      inputMap.put(KeyStroke.getKeyStroke("meta shift pressed SHIFT"), ActionType.ACTIVATE_ALIGNMENT);
 
1207
      inputMap.put(KeyStroke.getKeyStroke("meta released SHIFT"), ActionType.DEACTIVATE_ALIGNMENT);
1129
1208
    } else {
1130
 
      // Under other systems, duplication with Ctrl key 
1131
 
      inputMap.put(KeyStroke.getKeyStroke("control pressed CONTROL"), ActionType.ACTIVATE_DUPLICATION);
1132
 
      inputMap.put(KeyStroke.getKeyStroke("released CONTROL"), ActionType.DEACTIVATE_DUPLICATION);
1133
 
      inputMap.put(KeyStroke.getKeyStroke("shift control pressed CONTROL"), ActionType.ACTIVATE_DUPLICATION);
1134
 
      inputMap.put(KeyStroke.getKeyStroke("shift released CONTROL"), ActionType.DEACTIVATE_DUPLICATION);
1135
 
      inputMap.put(KeyStroke.getKeyStroke("control ESCAPE"), ActionType.ESCAPE);
1136
 
      inputMap.put(KeyStroke.getKeyStroke("control shift pressed SHIFT"), ActionType.TOGGLE_MAGNETISM_ON);
1137
 
      inputMap.put(KeyStroke.getKeyStroke("control released SHIFT"), ActionType.TOGGLE_MAGNETISM_OFF);
 
1209
      inputMap.put(KeyStroke.getKeyStroke("control shift pressed SHIFT"), ActionType.ACTIVATE_ALIGNMENT);
 
1210
      inputMap.put(KeyStroke.getKeyStroke("control released SHIFT"), ActionType.DEACTIVATE_ALIGNMENT);
 
1211
      inputMap.put(KeyStroke.getKeyStroke("shift released ALT"), ActionType.ACTIVATE_ALIGNMENT);
 
1212
      inputMap.put(KeyStroke.getKeyStroke("control shift released ALT"), ActionType.ACTIVATE_ALIGNMENT);
1138
1213
    }
1139
1214
  }
1140
1215
  
1211
1286
        controller.toggleMagnetism(this.toggle);
1212
1287
      }
1213
1288
    }
 
1289
    // Alignment action
 
1290
    class SetAlignmentActivatedAction extends AbstractAction {
 
1291
      private final boolean alignmentActivated;
 
1292
      
 
1293
      public SetAlignmentActivatedAction(boolean alignmentActivated) {
 
1294
        this.alignmentActivated = alignmentActivated;
 
1295
      }
 
1296
      
 
1297
      public void actionPerformed(ActionEvent ev) {
 
1298
        controller.setAlignmentActivated(this.alignmentActivated);
 
1299
      }
 
1300
    }
1214
1301
    // Duplication action
1215
1302
    class SetDuplicationActivatedAction extends AbstractAction {
1216
1303
      private final boolean duplicationActivated;
1248
1335
    actionMap.put(ActionType.MOVE_SELECTION_FAST_RIGHT, new MoveSelectionAction(10, 0));
1249
1336
    actionMap.put(ActionType.TOGGLE_MAGNETISM_ON, new ToggleMagnetismAction(true));
1250
1337
    actionMap.put(ActionType.TOGGLE_MAGNETISM_OFF, new ToggleMagnetismAction(false));
 
1338
    actionMap.put(ActionType.ACTIVATE_ALIGNMENT, new SetAlignmentActivatedAction(true));
 
1339
    actionMap.put(ActionType.DEACTIVATE_ALIGNMENT, new SetAlignmentActivatedAction(false));
1251
1340
    actionMap.put(ActionType.ACTIVATE_DUPLICATION, new SetDuplicationActivatedAction(true));
1252
1341
    actionMap.put(ActionType.DEACTIVATE_DUPLICATION, new SetDuplicationActivatedAction(false));
1253
1342
    actionMap.put(ActionType.ACTIVATE_EDITIION, new SetEditionActivatedAction(true));
1338
1427
   */ 
1339
1428
  protected Cursor createCustomCursor(URL smallCursorImageUrl, 
1340
1429
                                      URL largeCursorImageUrl,
 
1430
                                      float xCursorHotSpot,
1341
1431
                                      float yCursorHotSpot,
1342
 
                                      float xCursorHotSpot,
1343
1432
                                      String cursorName,
1344
1433
                                      Cursor defaultCursor) {
1345
 
    if (GraphicsEnvironment.isHeadless()) {
1346
 
      return defaultCursor;
1347
 
    }
1348
 
    // Retrieve system cursor size
1349
 
    Dimension cursorSize = getToolkit().getBestCursorSize(16, 16);
1350
 
    URL cursorImageResource;
1351
 
    // If returned cursor size is 0, system doesn't support custom cursor  
1352
 
    if (cursorSize.width == 0) {      
1353
 
      return defaultCursor;      
1354
 
    } else {
1355
 
      // Use a different cursor image depending on system cursor size 
1356
 
      if (cursorSize.width > 16) {
1357
 
        cursorImageResource = largeCursorImageUrl;
1358
 
      } else {
1359
 
        cursorImageResource = smallCursorImageUrl;
1360
 
      }
1361
 
      try {
1362
 
        // Read cursor image
1363
 
        BufferedImage cursorImage = ImageIO.read(cursorImageResource);
1364
 
        // Create custom cursor from image
1365
 
        return getToolkit().createCustomCursor(cursorImage, 
1366
 
            new Point(Math.round(cursorSize.width * xCursorHotSpot), 
1367
 
                      Math.round(cursorSize.height * yCursorHotSpot)),
1368
 
            cursorName);
1369
 
      } catch (IOException ex) {
1370
 
        throw new IllegalArgumentException("Unknown resource " + cursorImageResource);
1371
 
      }
1372
 
    }
 
1434
    return SwingTools.createCustomCursor(smallCursorImageUrl, largeCursorImageUrl, 
 
1435
        xCursorHotSpot, yCursorHotSpot, cursorName, defaultCursor);
1373
1436
  }
1374
1437
 
1375
1438
  /**
1405
1468
      if (this.backgroundImageCache != null) {
1406
1469
        BackgroundImage backgroundImage = this.home.getBackgroundImage();
1407
1470
        if (backgroundImage != null) {
 
1471
          this.planBoundsCache.add(-backgroundImage.getXOrigin(), -backgroundImage.getYOrigin());
1408
1472
          this.planBoundsCache.add(this.backgroundImageCache.getWidth() * backgroundImage.getScale() - backgroundImage.getXOrigin(),
1409
1473
              this.backgroundImageCache.getHeight() * backgroundImage.getScale() - backgroundImage.getYOrigin());
1410
1474
        }
1411
1475
        for (Level level : this.home.getLevels()) {
1412
1476
          BackgroundImage levelBackgroundImage = level.getBackgroundImage();
1413
1477
          if (levelBackgroundImage != null) {
 
1478
            this.planBoundsCache.add(-levelBackgroundImage.getXOrigin(), -levelBackgroundImage.getYOrigin());
1414
1479
            this.planBoundsCache.add(this.backgroundImageCache.getWidth() * levelBackgroundImage.getScale() - levelBackgroundImage.getXOrigin(),
1415
1480
                this.backgroundImageCache.getHeight() * levelBackgroundImage.getScale() - levelBackgroundImage.getYOrigin());
1416
1481
          }
1759
1824
    if (printedItemBounds != null) {
1760
1825
      float imageableWidthCm = LengthUnit.inchToCentimeter((float)pageFormat.getImageableWidth() / 72);
1761
1826
      float imageableHeightCm = LengthUnit.inchToCentimeter((float)pageFormat.getImageableHeight() / 72);
1762
 
      float extraMargin = getStrokeWidthExtraMargin(printedItems);
 
1827
      float extraMargin = getStrokeWidthExtraMargin(printedItems, PaintMode.PRINT);
1763
1828
      // Compute the largest integer scale possible
1764
1829
      int scaleInverse = (int)Math.ceil(Math.max(
1765
1830
          (printedItemBounds.getWidth() + 2 * extraMargin) / imageableWidthCm,
1774
1839
   * Returns the margin that should be added around home items bounds to ensure their
1775
1840
   * line stroke width is always fully visible.
1776
1841
   */
1777
 
  private float getStrokeWidthExtraMargin(List<Selectable> items) {
1778
 
    float extraMargin = BORDER_STROKE_WIDTH / 2;
1779
 
    if (Home.getWallsSubList(items).size() > 0
1780
 
        || Home.getRoomsSubList(items).size() > 0) {
1781
 
      extraMargin = WALL_STROKE_WIDTH / 2;
1782
 
    }
1783
 
    return extraMargin;
 
1842
  private float getStrokeWidthExtraMargin(List<Selectable> items, PaintMode paintMode) {
 
1843
    float extraMargin = BORDER_STROKE_WIDTH;
 
1844
    if (Home.getFurnitureSubList(items).size() > 0) {
 
1845
      extraMargin = Math.max(extraMargin, getStrokeWidth(HomePieceOfFurniture.class, paintMode));
 
1846
    } 
 
1847
    if (Home.getWallsSubList(items).size() > 0) {
 
1848
      extraMargin = Math.max(extraMargin, getStrokeWidth(Wall.class, paintMode));
 
1849
    } 
 
1850
    if (Home.getRoomsSubList(items).size() > 0) {
 
1851
      extraMargin = Math.max(extraMargin, getStrokeWidth(Room.class, paintMode));
 
1852
    }
 
1853
    if (Home.getDimensionLinesSubList(items).size() > 0) {
 
1854
      extraMargin = Math.max(extraMargin, getStrokeWidth(DimensionLine.class, paintMode));
 
1855
    }
 
1856
    return extraMargin / 2;
 
1857
  }
 
1858
  
 
1859
  /**
 
1860
   * Returns the stroke width used to paint an item of the given class.
 
1861
   */
 
1862
  private float getStrokeWidth(Class<? extends Selectable> itemClass, PaintMode paintMode) {
 
1863
    float strokeWidth; 
 
1864
    if (Wall.class.isAssignableFrom(itemClass)
 
1865
        || Room.class.isAssignableFrom(itemClass)) {
 
1866
      strokeWidth = WALL_STROKE_WIDTH;
 
1867
    } else {
 
1868
      strokeWidth = BORDER_STROKE_WIDTH;
 
1869
    }
 
1870
    if (paintMode == PaintMode.PRINT) {
 
1871
      strokeWidth *= 0.5;
 
1872
    }
 
1873
    return strokeWidth;
1784
1874
  }
1785
1875
  
1786
1876
  /**
1833
1923
      // Change coordinates system to paper imageable origin
1834
1924
      g2D.translate(imageableX - columnIndex * imageableWidth, imageableY - rowIndex * imageableHeight);
1835
1925
      g2D.scale(printScale, printScale);
1836
 
      float extraMargin = getStrokeWidthExtraMargin(printedItems);
 
1926
      float extraMargin = getStrokeWidthExtraMargin(printedItems, PaintMode.PRINT);
1837
1927
      g2D.translate(-printedItemBounds.getMinX() + extraMargin,
1838
1928
          -printedItemBounds.getMinY() + extraMargin);
1839
1929
      // Center plan in component if possible
1867
1957
    } else {
1868
1958
      // Use a scale of 1
1869
1959
      float clipboardScale = 1f;
1870
 
      float extraMargin = getStrokeWidthExtraMargin(this.home.getSelectedItems());
 
1960
      float extraMargin = getStrokeWidthExtraMargin(this.home.getSelectedItems(), PaintMode.CLIPBOARD);
1871
1961
      BufferedImage image = new BufferedImage((int)Math.ceil(selectionBounds.getWidth() * clipboardScale + 2 * extraMargin), 
1872
1962
              (int)Math.ceil(selectionBounds.getHeight() * clipboardScale + 2 * extraMargin), BufferedImage.TYPE_INT_RGB);      
1873
1963
      Graphics2D g2D = (Graphics2D)image.getGraphics();
1911
2001
      }
1912
2002
      
1913
2003
      float svgScale = 1f;
1914
 
      float extraMargin = planComponent.getStrokeWidthExtraMargin(homeItems);
 
2004
      float extraMargin = planComponent.getStrokeWidthExtraMargin(homeItems, PaintMode.EXPORT);
1915
2005
      Dimension imageSize = new Dimension((int)Math.ceil(svgItemBounds.getWidth() * svgScale + 2 * extraMargin), 
1916
2006
          (int)Math.ceil(svgItemBounds.getHeight() * svgScale + 2 * extraMargin));
1917
2007
      
2109
2199
      if (this.otherLevelWallAreaCache != null) {
2110
2200
        Composite oldComposite = setTransparency(g2D, 
2111
2201
            this.preferences.isGridVisible() ? 0.2f : 0.1f);
2112
 
        fillAndDrawArea(g2D, this.otherLevelWallAreaCache, planScale, 
2113
 
            getWallPaint(planScale, backgroundColor, foregroundColor, this.preferences.getWallPattern()), foregroundColor);
 
2202
        fillAndDrawWallsArea(g2D, this.otherLevelWallAreaCache, planScale, 
 
2203
            getWallPaint(planScale, backgroundColor, foregroundColor, this.preferences.getWallPattern()), 
 
2204
            foregroundColor, PaintMode.PAINT);
2114
2205
        g2D.setComposite(oldComposite);
2115
2206
      }
2116
2207
    }
2154
2245
      xMax = convertXPixelToModel(getWidth());
2155
2246
      yMax = convertYPixelToModel(getHeight());
2156
2247
    }
2157
 
    if (OperatingSystem.isMacOSX()
2158
 
        && System.getProperty("apple.awt.graphics.UseQuartz", "false").equals("false")) {
2159
 
      // Draw grid with an image texture in under Mac OS X, because default 2D rendering engine 
 
2248
    boolean useGridImage = false;
 
2249
    try {
 
2250
      useGridImage = OperatingSystem.isMacOSX()
 
2251
          && System.getProperty("apple.awt.graphics.UseQuartz", "false").equals("false");
 
2252
    } catch (AccessControlException ex) {
 
2253
      // Unsigned applet
 
2254
    }
 
2255
    if (useGridImage) {
 
2256
      // Draw grid with an image texture under Mac OS X, because default 2D rendering engine 
2160
2257
      // is too slow and can't be replaced by Quartz engine in applet environment 
2161
2258
      int imageWidth = Math.round(mainGridSize * gridScale);
2162
2259
      BufferedImage gridImage = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_ARGB);
2212
2309
   */
2213
2310
  private float getMainGridSize(float gridScale) {
2214
2311
    float [] mainGridSizes;
2215
 
    if (this.preferences.getLengthUnit() == LengthUnit.INCH) {
 
2312
    LengthUnit lengthUnit = this.preferences.getLengthUnit();
 
2313
    if (lengthUnit == LengthUnit.INCH 
 
2314
        || lengthUnit == LengthUnit.INCH_DECIMALS) {
2216
2315
      // Use a grid in inch and foot with a minimum grid increment of 1 inch
2217
2316
      float oneFoot = 2.54f * 12;
2218
2317
      mainGridSizes = new float [] {oneFoot, 3 * oneFoot, 6 * oneFoot, 
2234
2333
   */
2235
2334
  private float getGridSize(float gridScale) {
2236
2335
    float [] gridSizes;
2237
 
    if (this.preferences.getLengthUnit() == LengthUnit.INCH) {
 
2336
    LengthUnit lengthUnit = this.preferences.getLengthUnit();
 
2337
    if (lengthUnit == LengthUnit.INCH 
 
2338
        || lengthUnit == LengthUnit.INCH_DECIMALS) {
2238
2339
      // Use a grid in inch and foot with a minimum grid increment of 1 inch
2239
2340
      float oneFoot = 2.54f * 12;
2240
2341
      gridSizes = new float [] {2.54f, 5.08f, 7.62f, 15.24f, oneFoot, 3 * oneFoot, 6 * oneFoot, 
2484
2585
        ? Color.WHITE
2485
2586
        : Color.GRAY;
2486
2587
    // Draw rooms area
2487
 
    g2D.setStroke(new BasicStroke(WALL_STROKE_WIDTH / planScale));
 
2588
    g2D.setStroke(new BasicStroke(getStrokeWidth(Room.class, paintMode) / planScale));
2488
2589
    for (Room room : this.sortedLevelRooms) { 
2489
2590
      boolean selectedRoom = selectedItems.contains(room);
2490
2591
      // In clipboard paint mode, paint room only if it is selected
2663
2764
    
2664
2765
    // Draw rooms area
2665
2766
    g2D.setPaint(foregroundColor);
2666
 
    g2D.setStroke(new BasicStroke(WALL_STROKE_WIDTH / planScale));
 
2767
    g2D.setStroke(new BasicStroke(getStrokeWidth(Room.class, PaintMode.PAINT) / planScale));
2667
2768
    for (Room room : rooms) { 
2668
2769
      if (isViewableAtSelectedLevel(room)) {
2669
2770
        g2D.draw(getShape(room.getPoints()));
2814
2915
        : planScale;
2815
2916
    for (Map.Entry<Collection<Wall>, Area> areaEntry : wallAreas.entrySet()) {
2816
2917
      TextureImage wallPattern = areaEntry.getKey().iterator().next().getPattern();
2817
 
      fillAndDrawArea(g2D, areaEntry.getValue(), planScale, 
 
2918
      fillAndDrawWallsArea(g2D, areaEntry.getValue(), planScale, 
2818
2919
          getWallPaint(wallPaintScale, backgroundColor, foregroundColor, 
2819
 
              wallPattern != null ? wallPattern : this.preferences.getWallPattern()), foregroundColor);
 
2920
              wallPattern != null ? wallPattern : this.preferences.getWallPattern()), foregroundColor, paintMode);
2820
2921
    }
2821
2922
  }
2822
2923
 
2823
2924
  /**
2824
2925
   * Fills and paints the given area.
2825
2926
   */
2826
 
  private void fillAndDrawArea( Graphics2D g2D, Area area, float planScale, Paint fillPaint, Paint drawPaint) {
 
2927
  private void fillAndDrawWallsArea(Graphics2D g2D, Area area, float planScale, Paint fillPaint, 
 
2928
                                    Paint drawPaint, PaintMode paintMode) {
2827
2929
    // Fill walls area
2828
2930
    g2D.setPaint(fillPaint);
2829
2931
    g2D.fill(area);
2830
2932
    // Draw walls area
2831
2933
    g2D.setPaint(drawPaint);
2832
 
    g2D.setStroke(new BasicStroke(WALL_STROKE_WIDTH / planScale));
 
2934
    g2D.setStroke(new BasicStroke(getStrokeWidth(Wall.class, paintMode) / planScale));
2833
2935
    g2D.draw(area);
2834
2936
  }
2835
2937
  
2922
3024
    }
2923
3025
    // Draw walls area
2924
3026
    g2D.setPaint(foregroundColor);
2925
 
    g2D.setStroke(new BasicStroke(WALL_STROKE_WIDTH / planScale));
 
3027
    g2D.setStroke(new BasicStroke(getStrokeWidth(Wall.class, PaintMode.PAINT) / planScale));
2926
3028
    for (Area area : getWallAreas(walls).values()) {
2927
3029
      g2D.draw(area);
2928
3030
    }
3094
3196
                              Color furnitureOutlineColor,
3095
3197
                              PaintMode paintMode, boolean paintIcon) {    
3096
3198
    if (!furniture.isEmpty()) {
3097
 
      BasicStroke pieceBorderStroke = new BasicStroke(BORDER_STROKE_WIDTH / planScale);
 
3199
      BasicStroke pieceBorderStroke = new BasicStroke(getStrokeWidth(HomePieceOfFurniture.class, paintMode) / planScale);
3098
3200
      Boolean allFurnitureViewedFromTop = null;
3099
3201
      // Draw furniture
3100
3202
      for (HomePieceOfFurniture piece : furniture) {
3117
3219
            if (piece instanceof HomeDoorOrWindow) {
3118
3220
              HomeDoorOrWindow doorOrWindow = (HomeDoorOrWindow)piece;
3119
3221
              pieceShape2D = getDoorOrWindowShapeAtWallIntersection(doorOrWindow);
3120
 
              paintDoorOrWindowSashes(g2D, doorOrWindow, planScale, foregroundColor);
 
3222
              paintDoorOrWindowSashes(g2D, doorOrWindow, planScale, foregroundColor, paintMode);
3121
3223
            } else {
3122
3224
              pieceShape2D = pieceShape;
3123
3225
            }
3210
3312
   * Paints the sashes of a door or a window.
3211
3313
   */
3212
3314
  private void paintDoorOrWindowSashes(Graphics2D g2D, HomeDoorOrWindow doorOrWindow, float planScale, 
3213
 
                                       Color foregroundColor) {
3214
 
    BasicStroke sashBorderStroke = new BasicStroke(BORDER_STROKE_WIDTH / planScale);
 
3315
                                       Color foregroundColor, PaintMode paintMode) {
 
3316
    BasicStroke sashBorderStroke = new BasicStroke(getStrokeWidth(HomePieceOfFurniture.class, paintMode) / planScale);
3215
3317
    g2D.setPaint(foregroundColor);
3216
3318
    g2D.setStroke(sashBorderStroke);
3217
3319
    for (Sash sash : doorOrWindow.getSashes()) {
3293
3395
                                     Paint selectionOutlinePaint, Stroke selectionOutlineStroke, 
3294
3396
                                     Paint indicatorPaint, float planScale, 
3295
3397
                                     Color foregroundColor) {
3296
 
    BasicStroke pieceBorderStroke = new BasicStroke(BORDER_STROKE_WIDTH / planScale);
3297
 
    BasicStroke pieceFrontBorderStroke = new BasicStroke(4 * BORDER_STROKE_WIDTH / planScale, 
 
3398
    BasicStroke pieceBorderStroke = new BasicStroke(getStrokeWidth(HomePieceOfFurniture.class, PaintMode.PAINT) / planScale);
 
3399
    BasicStroke pieceFrontBorderStroke = new BasicStroke(4 * getStrokeWidth(HomePieceOfFurniture.class, PaintMode.PAINT) / planScale, 
3298
3400
        BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
3299
3401
    for (HomePieceOfFurniture piece : Home.getFurnitureSubList(items)) {
3300
3402
      if (piece.isVisible() 
3510
3612
 
3511
3613
    // Draw dimension lines
3512
3614
    g2D.setPaint(foregroundColor);
3513
 
    BasicStroke dimensionLineStroke = new BasicStroke(BORDER_STROKE_WIDTH / planScale);
 
3615
    BasicStroke dimensionLineStroke = new BasicStroke(getStrokeWidth(DimensionLine.class, paintMode) / planScale);
3514
3616
    // Change font size
3515
3617
    Font previousFont = g2D.getFont();
3516
3618
    for (DimensionLine dimensionLine : dimensionLines) {
4211
4313
      g2D.setPaint(backgroundColor);
4212
4314
      g2D.fill(scaledCameraBody);
4213
4315
      g2D.setPaint(foregroundColor);
4214
 
      BasicStroke stroke = new BasicStroke(BORDER_STROKE_WIDTH / planScale);
 
4316
      BasicStroke stroke = new BasicStroke(getStrokeWidth(ObserverCamera.class, PaintMode.PAINT) / planScale);
4215
4317
      g2D.setStroke(stroke);
4216
4318
      g2D.draw(scaledCameraBody);
4217
4319
  
4658
4760
      if (toolTipEditedProperties [i] == PlanController.EditableProperty.ANGLE
4659
4761
          || toolTipEditedProperties [i] == PlanController.EditableProperty.ARC_EXTENT) {
4660
4762
        unitLabel = new JLabel(this.preferences.getLocalizedString(PlanComponent.class, "degreeLabel.text"));
4661
 
      } else if (this.preferences.getLengthUnit() != LengthUnit.INCH) {
 
4763
      } else if (this.preferences.getLengthUnit() != LengthUnit.INCH
 
4764
                 || this.preferences.getLengthUnit() != LengthUnit.INCH_DECIMALS) {
4662
4765
        unitLabel = new JLabel(" " + this.preferences.getLengthUnit().getName());
4663
4766
      }
4664
4767
      
5181
5284
      if (Math.abs(value) < 1E-5) {
5182
5285
        value = 0; // Avoid "-0" text
5183
5286
      }
5184
 
      if (preferences.getLengthUnit() == LengthUnit.INCH) {
 
5287
      LengthUnit lengthUnit = preferences.getLengthUnit();
 
5288
      if (lengthUnit == LengthUnit.INCH 
 
5289
          || lengthUnit == LengthUnit.INCH_DECIMALS) {
5185
5290
        text = format.format(LengthUnit.centimeterToFoot((float)value)) + "'"; 
5186
5291
      } else {
5187
5292
        text = format.format(value / 100);