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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Gabriele Giacone
  • Date: 2012-09-18 13:36:44 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20120918133644-smm7jyifj8ywj3rd
Tags: 3.6+dfsg-1
* New upstream release (Closes: #687996).
* B-D on default-jdk, runtime on default-jre (Closes: #684298).
* Remove gamma correction from icons (Closes: #687823).
* Fix binary xz compression.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
package com.eteks.sweethome3d.swing;
21
21
 
22
22
import java.awt.Component;
 
23
import java.awt.Cursor;
 
24
import java.awt.Dimension;
 
25
import java.awt.EventQueue;
23
26
import java.awt.Font;
24
27
import java.awt.Graphics;
25
28
import java.awt.Graphics2D;
 
29
import java.awt.Point;
 
30
import java.awt.Rectangle;
26
31
import java.awt.RenderingHints;
27
32
import java.awt.dnd.DnDConstants;
28
 
import java.awt.event.MouseAdapter;
29
33
import java.awt.event.MouseEvent;
30
34
import java.awt.event.MouseMotionAdapter;
31
35
import java.awt.image.BufferedImage;
32
36
import java.io.IOException;
33
37
import java.lang.ref.WeakReference;
 
38
import java.net.MalformedURLException;
 
39
import java.net.URL;
34
40
import java.util.ArrayList;
35
41
import java.util.Collections;
36
42
import java.util.List;
37
43
 
38
44
import javax.imageio.ImageIO;
39
45
import javax.swing.Icon;
40
 
import javax.swing.JLabel;
 
46
import javax.swing.JComponent;
 
47
import javax.swing.JEditorPane;
41
48
import javax.swing.JTree;
42
49
import javax.swing.SwingUtilities;
43
50
import javax.swing.ToolTipManager;
 
51
import javax.swing.event.MouseInputAdapter;
44
52
import javax.swing.event.TreeModelEvent;
45
53
import javax.swing.event.TreeModelListener;
46
54
import javax.swing.event.TreeSelectionEvent;
47
55
import javax.swing.event.TreeSelectionListener;
 
56
import javax.swing.text.AttributeSet;
 
57
import javax.swing.text.Element;
 
58
import javax.swing.text.html.HTML;
 
59
import javax.swing.text.html.HTMLDocument;
48
60
import javax.swing.tree.DefaultTreeCellRenderer;
 
61
import javax.swing.tree.TreeCellRenderer;
49
62
import javax.swing.tree.TreeModel;
50
63
import javax.swing.tree.TreePath;
51
64
 
102
115
    if (controller != null) {
103
116
      updateTreeSelectedFurniture(catalog, controller);
104
117
      addSelectionListeners(catalog, controller);
105
 
      addMouseListener(controller);
 
118
      addMouseListeners(controller);
106
119
    }
107
120
    ToolTipManager.sharedInstance().registerComponent(this);
108
121
    // Remove Select all action
191
204
  }
192
205
  
193
206
  /**
194
 
   * Adds a double click mouse listener to modify selected furniture.
 
207
   * Adds mouse listeners to modify selected furniture and manage links in piece information.
195
208
   */
196
 
  private void addMouseListener(final FurnitureCatalogController controller) {
197
 
    addMouseListener(new MouseAdapter () {
 
209
  private void addMouseListeners(final FurnitureCatalogController controller) {
 
210
    final Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
 
211
    MouseInputAdapter mouseListener = new MouseInputAdapter() {
198
212
        @Override
199
213
        public void mouseClicked(MouseEvent ev) {
200
 
          if (ev.getClickCount() == 2) {
201
 
            TreePath clickedPath = getPathForLocation(ev.getX(), ev.getY());
202
 
            if (clickedPath != null
203
 
                && clickedPath.getLastPathComponent() instanceof CatalogPieceOfFurniture) {
204
 
              controller.modifySelectedFurniture();
205
 
            }
206
 
          }
207
 
        }
208
 
      });
 
214
          if (SwingUtilities.isLeftMouseButton(ev)) {
 
215
            if (ev.getClickCount() == 2) {
 
216
              TreePath clickedPath = getPathForLocation(ev.getX(), ev.getY());
 
217
              if (clickedPath != null
 
218
                  && clickedPath.getLastPathComponent() instanceof CatalogPieceOfFurniture) {
 
219
                controller.modifySelectedFurniture();
 
220
              }
 
221
            } else if (getCellRenderer() instanceof CatalogCellRenderer) {
 
222
              URL url = ((CatalogCellRenderer)getCellRenderer()).getURLAt(ev.getPoint(), (JTree)ev.getSource());
 
223
              if (url != null) {
 
224
                SwingTools.showDocumentInBrowser(url);
 
225
              }
 
226
            }
 
227
          }
 
228
        }
 
229
        
 
230
        @Override
 
231
        public void mouseMoved(MouseEvent ev) {
 
232
          if (getCellRenderer() instanceof CatalogCellRenderer) {
 
233
            URL url = ((CatalogCellRenderer)getCellRenderer()).getURLAt(ev.getPoint(), (JTree)ev.getSource());
 
234
            if (url != null) {
 
235
              EventQueue.invokeLater(new Runnable() {                  
 
236
                  public void run() {
 
237
                    setCursor(handCursor);
 
238
                  }
 
239
                });
 
240
            }
 
241
          }
 
242
          setCursor(Cursor.getDefaultCursor());
 
243
        }
 
244
      };
 
245
    addMouseListener(mouseListener);
 
246
    addMouseMotionListener(mouseListener);
209
247
  }
210
248
 
211
249
  /**
219
257
        && path.getPathCount() == 3) {
220
258
      CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)path.getLastPathComponent();
221
259
      String tooltip = "<html><table><tr><td align='center'><b>" + piece.getName() + "</b>";
222
 
      if (piece.getCreator() != null) {
 
260
      String creator = piece.getCreator();
 
261
      if (creator != null) {
223
262
        tooltip += "<br>" + this.preferences.getLocalizedString(FurnitureCatalogTree.class, 
224
 
            "tooltipCreator", piece.getCreator() + "</td></tr>");
 
263
            "tooltipCreator", creator + "</td></tr>");
225
264
      }
226
265
      if (piece.getIcon() instanceof URLContent) {
227
266
        try {
248
287
  /**
249
288
   * Cell renderer for this catalog tree.
250
289
   */
251
 
  private static class CatalogCellRenderer extends DefaultTreeCellRenderer {
252
 
    private static final int DEFAULT_ICON_HEIGHT = 32;
253
 
    private Font defaultFont;
254
 
    private Font modifiablePieceFont;
255
 
    
256
 
    @Override
 
290
  private class CatalogCellRenderer extends JComponent implements TreeCellRenderer {
 
291
    private static final int        DEFAULT_ICON_HEIGHT = 32;
 
292
    private Font                    defaultFont;
 
293
    private Font                    modifiablePieceFont;
 
294
    private DefaultTreeCellRenderer nameLabel;
 
295
    private JEditorPane             informationPane;
 
296
    
 
297
    public CatalogCellRenderer() {
 
298
      setLayout(null);
 
299
      this.nameLabel = new DefaultTreeCellRenderer();
 
300
      this.informationPane = new JEditorPane("text/html", null);
 
301
      this.informationPane.setOpaque(false);
 
302
      this.informationPane.setEditable(false);
 
303
      add(this.nameLabel);
 
304
      add(this.informationPane);
 
305
    }
 
306
    
257
307
    public Component getTreeCellRendererComponent(JTree tree, 
258
308
        Object value, boolean selected, boolean expanded, 
259
309
        boolean leaf, int row, boolean hasFocus) {
260
 
      // Get default label with its icon, background and focus colors 
261
 
      JLabel label = (JLabel)super.getTreeCellRendererComponent( 
 
310
      // Configure name label with its icon, background and focus colors 
 
311
      this.nameLabel.getTreeCellRendererComponent( 
262
312
          tree, value, selected, expanded, leaf, row, hasFocus);
263
313
      // Initialize fonts if not done
264
314
      if (this.defaultFont == null) {
265
 
        this.defaultFont = label.getFont();
 
315
        this.defaultFont = this.nameLabel.getFont();
 
316
        String bodyRule = "body { font-family: " + this.defaultFont.getFamily() + "; " 
 
317
            + "font-size: " + this.defaultFont.getSize() + "pt; " 
 
318
            + "top-margin: 0; }";
 
319
        ((HTMLDocument)this.informationPane.getDocument()).getStyleSheet().addRule(bodyRule);
266
320
        this.modifiablePieceFont = 
267
 
            new Font(this.defaultFont.getFontName(), Font.ITALIC, this.defaultFont.getSize());
268
 
        
 
321
            new Font(this.defaultFont.getFontName(), Font.ITALIC, this.defaultFont.getSize());        
269
322
      }
270
323
      // If node is a category, change label text
271
324
      if (value instanceof FurnitureCategory) {
272
 
        label.setText(((FurnitureCategory)value).getName());
273
 
        label.setFont(this.defaultFont);
 
325
        this.nameLabel.setText(((FurnitureCategory)value).getName());
 
326
        this.nameLabel.setFont(this.defaultFont);
 
327
        this.informationPane.setVisible(false);
274
328
      } 
275
329
      // Else if node is a piece of furniture, change label text and icon
276
330
      else if (value instanceof CatalogPieceOfFurniture) {
277
331
        CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)value;
278
 
        label.setText(piece.getName());
279
 
        label.setIcon(getLabelIcon(tree, piece.getIcon()));
280
 
        label.setFont(piece.isModifiable() 
 
332
        this.nameLabel.setText(piece.getName());
 
333
        this.nameLabel.setIcon(getLabelIcon(tree, piece.getIcon()));
 
334
        this.nameLabel.setFont(piece.isModifiable() 
281
335
            ? this.modifiablePieceFont : this.defaultFont);
282
 
      }
283
 
      return label;
 
336
        
 
337
        String information = piece.getInformation();
 
338
        if (information != null) {
 
339
          this.informationPane.setText(information);
 
340
          this.informationPane.setVisible(true);
 
341
        } else {
 
342
          this.informationPane.setVisible(false);
 
343
        }
 
344
      }
 
345
      return this;
 
346
    }
 
347
    
 
348
    @Override
 
349
    public void doLayout() {
 
350
      Dimension namePreferredSize = this.nameLabel.getPreferredSize();
 
351
      this.nameLabel.setSize(namePreferredSize);
 
352
      if (this.informationPane.isVisible()) {
 
353
        Dimension informationPreferredSize = this.informationPane.getPreferredSize();
 
354
        this.informationPane.setBounds(namePreferredSize.width + 2, 
 
355
            (namePreferredSize.height - informationPreferredSize.height) / 2,
 
356
            informationPreferredSize.width, namePreferredSize.height);
 
357
      }
 
358
    }
 
359
    
 
360
    @Override
 
361
    public Dimension getPreferredSize() {
 
362
      Dimension preferredSize = this.nameLabel.getPreferredSize();
 
363
      if (this.informationPane.isVisible()) {
 
364
        preferredSize.width += 2 + this.informationPane.getPreferredSize().width;
 
365
      }
 
366
      return preferredSize;
 
367
    }
 
368
    
 
369
    /**
 
370
     * The following methods are overridden for performance reasons.
 
371
     */
 
372
    @Override
 
373
    public void revalidate() {      
 
374
    }
 
375
    
 
376
    @Override
 
377
    public void repaint(long tm, int x, int y, int width, int height) {      
 
378
    }
 
379
 
 
380
    @Override
 
381
    public void repaint(Rectangle r) {      
 
382
    }
 
383
 
 
384
    @Override
 
385
    public void repaint() {      
284
386
    }
285
387
 
286
388
    /**
289
391
     * @param content the content of an image.
290
392
     */
291
393
    private Icon getLabelIcon(JTree tree, Content content) {
292
 
      int rowHeight = tree.isFixedRowHeight()
293
 
                         ? tree.getRowHeight()
294
 
                         : DEFAULT_ICON_HEIGHT;
295
 
      return IconManager.getInstance().getIcon(content, rowHeight, tree);
 
394
      return IconManager.getInstance().getIcon(content, getRowHeight(tree), tree);
 
395
    }
 
396
 
 
397
    /**
 
398
     * Returns the height of rows in tree.
 
399
     */
 
400
    private int getRowHeight(JTree tree) {
 
401
      return tree.isFixedRowHeight()
 
402
          ? tree.getRowHeight()
 
403
          : DEFAULT_ICON_HEIGHT;
296
404
    }
297
405
    
298
406
    @Override
299
 
    protected void paintComponent(Graphics g) {
 
407
    protected void paintChildren(Graphics g) {
300
408
      // Force text anti aliasing on texts
301
409
      ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
302
410
          RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
303
 
      super.paintComponent(g);
 
411
      super.paintChildren(g);
 
412
    }
 
413
 
 
414
    public URL getURLAt(Point point, JTree tree) {
 
415
      TreePath path = tree.getPathForLocation(point.x, point.y);
 
416
      if (path != null
 
417
          && path.getLastPathComponent() instanceof CatalogPieceOfFurniture) {
 
418
        CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)path.getLastPathComponent();
 
419
        String information = piece.getInformation();
 
420
        if (information != null) {
 
421
          int row = tree.getRowForPath(path);
 
422
          getTreeCellRendererComponent(tree, piece, false, false, false, row, false).doLayout();
 
423
          Rectangle rowBounds = tree.getRowBounds(row);
 
424
          point.x -= rowBounds.x + this.informationPane.getX(); 
 
425
          point.y -= rowBounds.y + this.informationPane.getY(); 
 
426
          if (point.x > 0 && point.y > 0) {
 
427
            // Search in information pane if point is over a HTML link
 
428
            int position = this.informationPane.viewToModel(point);
 
429
            if (position > 0) {
 
430
              HTMLDocument hdoc = (HTMLDocument)this.informationPane.getDocument();
 
431
              Element element = hdoc.getCharacterElement(position);
 
432
              AttributeSet a = element.getAttributes();
 
433
              AttributeSet anchor = (AttributeSet)a.getAttribute(HTML.Tag.A);
 
434
              if (anchor != null) {
 
435
                String href = (String)anchor.getAttribute(HTML.Attribute.HREF);
 
436
                if (href != null) {
 
437
                  try {
 
438
                    return new URL(href);
 
439
                  } catch (MalformedURLException ex) {
 
440
                    // Ignore malformed URL
 
441
                  }
 
442
                }
 
443
              }
 
444
            }
 
445
          }
 
446
        }
 
447
      }
 
448
      return null;
304
449
    }
305
450
  }
306
451
  
341
486
      if (parent instanceof FurnitureCatalog) {
342
487
        return Collections.binarySearch(((FurnitureCatalog)parent).getCategories(), (FurnitureCategory)child);
343
488
      } else {
344
 
        return Collections.binarySearch(((FurnitureCategory)parent).getFurniture(), (CatalogPieceOfFurniture)child);
 
489
        return ((FurnitureCategory)parent).getIndexOfPieceOfFurniture((CatalogPieceOfFurniture)child);
345
490
      }
346
491
    }
347
492