OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [tree/] [FixedHeightLayoutCache.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* FixedHeightLayoutCache.java -- Fixed cell height tree layout cache
2
Copyright (C) 2002, 2004, 2006,  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package javax.swing.tree;
39
 
40
import gnu.javax.swing.tree.GnuPath;
41
 
42
import java.awt.Rectangle;
43
import java.util.Enumeration;
44
import java.util.HashSet;
45
import java.util.Hashtable;
46
import java.util.LinkedList;
47
import java.util.Set;
48
import java.util.Vector;
49
 
50
import javax.swing.event.TreeModelEvent;
51
 
52
 
53
/**
54
 * The fixed height tree layout. This class assumes that all cells in the tree
55
 * have the same fixed height. This may be not the case, for instance, if leaves
56
 * and branches have different height, of if the tree rows may have arbitrary
57
 * variable height. This class will also work if the NodeDimensions are not
58
 * set.
59
 *
60
 * @author Audrius Meskauskas
61
 * @author Andrew Selkirk
62
 */
63
public class FixedHeightLayoutCache
64
                extends VariableHeightLayoutCache
65
{
66
  /**
67
   * The cached node record.
68
   */
69
  class NodeRecord
70
  {
71
    NodeRecord(int aRow, int aDepth, Object aNode, Object aParent)
72
    {
73
      row = aRow;
74
      depth = aDepth;
75
      parent = aParent;
76
      node = aNode;
77
 
78
      isExpanded = expanded.contains(aNode);
79
    }
80
 
81
    /**
82
     * The row, where the tree node is displayed.
83
     */
84
    final int row;
85
 
86
    /**
87
     * The nesting depth
88
     */
89
    final int depth;
90
 
91
    /**
92
     * The parent of the given node, null for the root node.
93
     */
94
    final Object parent;
95
 
96
    /**
97
     * This node.
98
     */
99
    final Object node;
100
 
101
    /**
102
     * True for the expanded nodes. The value is calculated in constructor.
103
     * Using this field saves one hashtable access operation.
104
     */
105
    final boolean isExpanded;
106
 
107
    /**
108
     * The cached bounds of the tree row.
109
     */
110
    Rectangle bounds;
111
 
112
    /**
113
     * The path from the tree top to the given node (computed under first
114
     * demand)
115
     */
116
    private TreePath path;
117
 
118
    /**
119
     * Get the path for this node. The derived class is returned,
120
     * making check for the last child of some parent easier.
121
     */
122
    TreePath getPath()
123
    {
124
      if (path == null)
125
        {
126
          boolean lastChild = false;
127
          if (parent != null)
128
            {
129
              int nc = treeModel.getChildCount(parent);
130
              if (nc > 0)
131
                {
132
                  int n = treeModel.getIndexOfChild(parent, node);
133
                  if (n == nc - 1)
134
                    lastChild = true;
135
                }
136
            }
137
 
138
          LinkedList<Object> lpath = new LinkedList<Object>();
139
          NodeRecord rp = this;
140
          while (rp != null)
141
            {
142
              lpath.addFirst(rp.node);
143
              if (rp.parent != null)
144
                {
145
                  Object parent = rp.parent;
146
                  rp = (NodeRecord) nodes.get(parent);
147
                  // Add the root node, even if it is not visible.
148
                  if (rp == null)
149
                    lpath.addFirst(parent);
150
                }
151
              else
152
                rp = null;
153
            }
154
          path = new GnuPath(lpath.toArray(), lastChild);
155
        }
156
      return path;
157
    }
158
 
159
    /**
160
     * Get the rectangle bounds (compute, if required).
161
     */
162
    Rectangle getBounds()
163
    {
164
      // This method may be called in the context when the tree rectangle is
165
      // not known. To work around this, it is assumed near infinitely large.
166
      if (bounds == null)
167
        bounds = getNodeDimensions(node, row, depth, isExpanded,
168
                                   new Rectangle());
169
      return bounds;
170
    }
171
  }
172
 
173
  /**
174
   * The set of all expanded tree nodes.
175
   */
176
  Set<Object> expanded = new HashSet<Object>();
177
 
178
  /**
179
   * Maps nodes to the row numbers.
180
   */
181
  Hashtable<Object,NodeRecord> nodes = new Hashtable<Object,NodeRecord>();
182
 
183
  /**
184
   * Maps row numbers to nodes.
185
   */
186
  Hashtable<Integer,Object> row2node = new Hashtable<Integer,Object>();
187
 
188
  /**
189
   * If true, the row map must be recomputed before using.
190
   */
191
  boolean dirty;
192
 
193
  /**
194
   * The cumulative height of all rows.
195
   */
196
  int totalHeight;
197
 
198
  /**
199
   * The maximal width.
200
   */
201
  int maximalWidth;
202
 
203
  /**
204
   * Creates the unitialised instance. Before using the class, the row height
205
   * must be set with the {@link #setRowHeight(int)} and the model must be set
206
   * with {@link #setModel(TreeModel)}. The node dimensions may not be set.
207
   */
208
  public FixedHeightLayoutCache()
209
  {
210
    // Nothing to do here.
211
  }
212
 
213
  /**
214
   * Get the total number of rows in the tree. Every displayed node occupies the
215
   * single row. The root node row is included if the root node is set as
216
   * visible (false by default).
217
   *
218
   * @return int the number of the displayed rows.
219
   */
220
  public int getRowCount()
221
  {
222
    if (dirty) update();
223
    return row2node.size();
224
  }
225
 
226
  /**
227
   * Refresh the row map.
228
   */
229
  private final void update()
230
  {
231
    nodes.clear();
232
    row2node.clear();
233
 
234
    totalHeight = maximalWidth = 0;
235
 
236
    Object root = treeModel.getRoot();
237
 
238
    if (rootVisible)
239
      {
240
        countRows(root, null, 0);
241
      }
242
    else
243
      {
244
        int sc = treeModel.getChildCount(root);
245
        for (int i = 0; i < sc; i++)
246
          {
247
            Object child = treeModel.getChild(root, i);
248
            countRows(child, root, 0);
249
          }
250
      }
251
    dirty = false;
252
  }
253
 
254
  /**
255
   * Recursively counts all rows in the tree.
256
   */
257
  private final void countRows(Object node, Object parent, int depth)
258
  {
259
    Integer n = new Integer(row2node.size());
260
    row2node.put(n, node);
261
 
262
    NodeRecord nr = new NodeRecord(n.intValue(), depth, node, parent);
263
    nodes.put(node, nr);
264
 
265
    // For expanded nodes and for the root node.
266
    if (expanded.contains(node))
267
      {
268
        int sc = treeModel.getChildCount(node);
269
        int deeper = depth + 1;
270
        for (int i = 0; i < sc; i++)
271
          {
272
            Object child = treeModel.getChild(node, i);
273
            countRows(child, node, deeper);
274
          }
275
      }
276
  }
277
 
278
  /**
279
   * Discard the bound information for the given path.
280
   *
281
   * @param path the path, for that the bound information must be recomputed.
282
   */
283
  public void invalidatePathBounds(TreePath path)
284
  {
285
    NodeRecord r = (NodeRecord) nodes.get(path.getLastPathComponent());
286
    if (r != null)
287
      r.bounds = null;
288
  }
289
 
290
  /**
291
   * Mark all cached information as invalid.
292
   */
293
  public void invalidateSizes()
294
  {
295
    dirty = true;
296
  }
297
 
298
  /**
299
   * Set the expanded state of the given path. The expansion states must be
300
   * always updated when expanding and colapsing the tree nodes. Otherwise
301
   * other methods will not work correctly after the nodes are collapsed or
302
   * expanded.
303
   *
304
   * @param path the tree path, for that the state is being set.
305
   * @param isExpanded the expanded state of the given path.
306
   */
307
  public void setExpandedState(TreePath path, boolean isExpanded)
308
  {
309
    if (isExpanded)
310
      expanded.add(path.getLastPathComponent());
311
    else
312
      expanded.remove(path.getLastPathComponent());
313
 
314
    dirty = true;
315
  }
316
 
317
  /**
318
   * Get the expanded state for the given tree path.
319
   *
320
   * @return true if the given path is expanded, false otherwise.
321
   */
322
  public boolean isExpanded(TreePath path)
323
  {
324
    return expanded.contains(path.getLastPathComponent());
325
  }
326
 
327
  /**
328
   * Get bounds for the given tree path.
329
   *
330
   * @param path the tree path
331
   * @param rect the rectangle that will be reused to return the result.
332
   * @return Rectangle the bounds of the last line, defined by the given path.
333
   */
334
  public Rectangle getBounds(TreePath path, Rectangle rect)
335
  {
336
    if (path == null)
337
      return null;
338
    if (dirty)
339
      update();
340
    Object last = path.getLastPathComponent();
341
    NodeRecord r = nodes.get(last);
342
    if (r == null)
343
    // This node is not visible.
344
      {
345
        rect.x = rect.y = rect.width = rect.height = 0;
346
      }
347
    else
348
      {
349
        if (r.bounds == null)
350
          {
351
            Rectangle dim = getNodeDimensions(last, r.row, r.depth,
352
                                              r.isExpanded, rect);
353
            r.bounds = dim;
354
          }
355
 
356
        rect.setRect(r.bounds);
357
      }
358
    return rect;
359
  }
360
 
361
  /**
362
   * Get the path, the last element of that is displayed in the given row.
363
   *
364
   * @param row the row
365
   * @return TreePath the path
366
   */
367
  public TreePath getPathForRow(int row)
368
  {
369
    if (dirty)
370
      update();
371
    Object last = row2node.get(new Integer(row));
372
    if (last == null)
373
      return null;
374
    else
375
      {
376
        NodeRecord r = nodes.get(last);
377
        return r.getPath();
378
      }
379
  }
380
 
381
  /**
382
   * Get the row, displaying the last node of the given path.
383
   *
384
   * @param path the path
385
   * @return int the row number or -1 if the end of the path is not visible.
386
   */
387
  public int getRowForPath(TreePath path)
388
  {
389
    if (path == null)
390
      return -1;
391
 
392
    if (dirty) update();
393
 
394
    NodeRecord r = nodes.get(path.getLastPathComponent());
395
    if (r == null)
396
      return - 1;
397
    else
398
      return r.row;
399
  }
400
 
401
  /**
402
   * Get the path, closest to the given point.
403
   *
404
   * @param x the point x coordinate
405
   * @param y the point y coordinate
406
   * @return the tree path, closest to the the given point
407
   */
408
  public TreePath getPathClosestTo(int x, int y)
409
  {
410
    if (dirty)
411
      update();
412
 
413
    // As the rows have arbitrary height, we need to iterate.
414
    NodeRecord best = null;
415
    NodeRecord r;
416
    Enumeration<NodeRecord> en = nodes.elements();
417
 
418
    int dist = Integer.MAX_VALUE;
419
 
420
    while (en.hasMoreElements() && dist > 0)
421
      {
422
        r = en.nextElement();
423
        if (best == null)
424
          {
425
            best = r;
426
            dist = distance(r.getBounds(), x, y);
427
          }
428
        else
429
          {
430
            int rr = distance(r.getBounds(), x, y);
431
            if (rr < dist)
432
              {
433
                best = r;
434
                dist = rr;
435
              }
436
          }
437
      }
438
 
439
    if (best == null)
440
      return null;
441
    else
442
      return best.getPath();
443
  }
444
 
445
  /**
446
   * Get the closest distance from this point till the given rectangle. Only
447
   * vertical distance is taken into consideration.
448
   */
449
  int distance(Rectangle r, int x, int y)
450
  {
451
    if (y < r.y)
452
      return r.y - y;
453
    else if (y > r.y + r.height)
454
      return y - (r.y + r.height);
455
    else
456
      return 0;
457
  }
458
 
459
  /**
460
   * Get the number of the visible childs for the given tree path. If the node
461
   * is not expanded, 0 is returned. Otherwise, the number of children is
462
   * obtained from the model as the number of children for the last path
463
   * component.
464
   *
465
   * @param path the tree path
466
   * @return int the number of the visible childs (for row).
467
   */
468
  public int getVisibleChildCount(TreePath path)
469
  {
470
    if (isExpanded(path))
471
      return 0;
472
    else
473
      return treeModel.getChildCount(path.getLastPathComponent());
474
  }
475
 
476
  /**
477
   * Get the enumeration over all visible paths that start from the given
478
   * parent path.
479
   *
480
   * @param parentPath the parent path
481
   * @return the enumeration over pathes
482
   */
483
  public Enumeration<TreePath> getVisiblePathsFrom(TreePath parentPath)
484
  {
485
    if (dirty)
486
      update();
487
    Vector<TreePath> p = new Vector<TreePath>(parentPath.getPathCount());
488
    Object node;
489
    NodeRecord nr;
490
 
491
    for (int i = 0; i < parentPath.getPathCount(); i++)
492
      {
493
        node = parentPath.getPathComponent(i);
494
        nr = nodes.get(node);
495
        if (nr.row >= 0)
496
          p.add((TreePath) node);
497
      }
498
    return p.elements();
499
  }
500
 
501
  /**
502
   * Return the expansion state of the given tree path. The expansion state
503
   * must be previously set with the
504
   * {@link #setExpandedState(TreePath, boolean)}
505
   *
506
   * @param path the path being checked
507
   * @return true if the last node of the path is expanded, false otherwise.
508
   */
509
  public boolean getExpandedState(TreePath path)
510
  {
511
    return expanded.contains(path.getLastPathComponent());
512
  }
513
 
514
  /**
515
   * The listener method, called when the tree nodes are changed.
516
   *
517
   * @param event the change event
518
   */
519
  public void treeNodesChanged(TreeModelEvent event)
520
  {
521
    dirty = true;
522
  }
523
 
524
  /**
525
   * The listener method, called when the tree nodes are inserted.
526
   *
527
   * @param event the change event
528
   */
529
  public void treeNodesInserted(TreeModelEvent event)
530
  {
531
    dirty = true;
532
  }
533
 
534
  /**
535
   * The listener method, called when the tree nodes are removed.
536
   *
537
   * @param event the change event
538
   */
539
  public void treeNodesRemoved(TreeModelEvent event)
540
  {
541
    dirty = true;
542
  }
543
 
544
  /**
545
   * Called when the tree structure has been changed.
546
   *
547
   * @param event the change event
548
   */
549
  public void treeStructureChanged(TreeModelEvent event)
550
  {
551
    dirty = true;
552
  }
553
 
554
  /**
555
   * Set the tree model that will provide the data.
556
   */
557
  public void setModel(TreeModel newModel)
558
  {
559
    treeModel = newModel;
560
    // The root node is expanded by default.
561
    expanded.add(treeModel.getRoot());
562
    dirty = true;
563
  }
564
 
565
  /**
566
   * Inform the instance if the tree root node is visible. If this method
567
   * is not called, it is assumed that the tree root node is not visible.
568
   *
569
   * @param visible true if the tree root node is visible, false
570
   * otherwise.
571
   */
572
  public void setRootVisible(boolean visible)
573
  {
574
    rootVisible = visible;
575
    dirty = true;
576
  }
577
 
578
  /**
579
   * Get the sum of heights for all rows.
580
   */
581
  public int getPreferredHeight()
582
  {
583
    if (dirty)
584
      update();
585
    totalHeight = 0;
586
    Enumeration<NodeRecord> en = nodes.elements();
587
    while (en.hasMoreElements())
588
      {
589
        NodeRecord nr = en.nextElement();
590
        Rectangle r = nr.getBounds();
591
        totalHeight += r.height;
592
      }
593
    return totalHeight;
594
  }
595
 
596
  /**
597
   * Get the maximal width.
598
   */
599
  public int getPreferredWidth(Rectangle value)
600
  {
601
    if (dirty)
602
      update();
603
 
604
    maximalWidth = 0;
605
    Enumeration<NodeRecord> en = nodes.elements();
606
    while (en.hasMoreElements())
607
      {
608
        NodeRecord nr = en.nextElement();
609
        Rectangle r = nr.getBounds();
610
        if (r.x + r.width > maximalWidth)
611
          maximalWidth = r.x + r.width;
612
      }
613
    return maximalWidth;
614
  }
615
 
616
  /**
617
   * Returns true if this layout supposes that all rows have the fixed
618
   * height.
619
   *
620
   * @return boolean true if all rows in the tree must have the fixed
621
   * height (true by default).
622
   */
623
  protected boolean isFixedRowHeight()
624
  {
625
    return true;
626
  }
627
 
628
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.