Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/demo/share/jfc/SampleTree/SampleTree.java
41149 views
1
/*
2
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
*
8
* - Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
*
11
* - Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* - Neither the name of Oracle nor the names of its
16
* contributors may be used to endorse or promote products derived
17
* from this software without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
*/
31
32
/*
33
* This source code is provided to illustrate the usage of a given feature
34
* or technique and has been deliberately simplified. Additional steps
35
* required for a production-quality application, such as security checks,
36
* input validation and proper error handling, might not be present in
37
* this sample code.
38
*/
39
40
41
42
import java.lang.reflect.InvocationTargetException;
43
import java.util.logging.Level;
44
import java.util.logging.Logger;
45
import javax.swing.*;
46
import javax.swing.event.*;
47
import java.awt.BorderLayout;
48
import java.awt.Color;
49
import java.awt.Dimension;
50
import java.awt.FlowLayout;
51
import java.awt.event.ActionEvent;
52
import java.awt.event.ActionListener;
53
import java.util.*;
54
import javax.swing.UIManager.LookAndFeelInfo;
55
import javax.swing.border.*;
56
import javax.swing.tree.*;
57
58
59
/**
60
* A demo for illustrating how to do different things with JTree.
61
* The data that this displays is rather boring, that is each node will
62
* have 7 children that have random names based on the fonts. Each node
63
* is then drawn with that font and in a different color.
64
* While the data isn't interesting the example illustrates a number
65
* of things:
66
*
67
* For an example of dynamicaly loading children refer to DynamicTreeNode.
68
* For an example of adding/removing/inserting/reloading refer to the inner
69
* classes of this class, AddAction, RemovAction, InsertAction and
70
* ReloadAction.
71
* For an example of creating your own cell renderer refer to
72
* SampleTreeCellRenderer.
73
* For an example of subclassing JTreeModel for editing refer to
74
* SampleTreeModel.
75
*
76
* @author Scott Violet
77
*/
78
public final class SampleTree {
79
80
/** Window for showing Tree. */
81
protected JFrame frame;
82
/** Tree used for the example. */
83
protected JTree tree;
84
/** Tree model. */
85
protected DefaultTreeModel treeModel;
86
87
/**
88
* Constructs a new instance of SampleTree.
89
*/
90
public SampleTree() {
91
// Trying to set Nimbus look and feel
92
try {
93
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
94
if ("Nimbus".equals(info.getName())) {
95
UIManager.setLookAndFeel(info.getClassName());
96
break;
97
}
98
}
99
} catch (Exception ignored) {
100
}
101
102
JMenuBar menuBar = constructMenuBar();
103
JPanel panel = new JPanel(true);
104
105
frame = new JFrame("SampleTree");
106
frame.getContentPane().add("Center", panel);
107
frame.setJMenuBar(menuBar);
108
frame.setBackground(Color.lightGray);
109
110
/* Create the JTreeModel. */
111
DefaultMutableTreeNode root = createNewNode("Root");
112
treeModel = new SampleTreeModel(root);
113
114
/* Create the tree. */
115
tree = new JTree(treeModel);
116
117
/* Enable tool tips for the tree, without this tool tips will not
118
be picked up. */
119
ToolTipManager.sharedInstance().registerComponent(tree);
120
121
/* Make the tree use an instance of SampleTreeCellRenderer for
122
drawing. */
123
tree.setCellRenderer(new SampleTreeCellRenderer());
124
125
/* Make tree ask for the height of each row. */
126
tree.setRowHeight(-1);
127
128
/* Put the Tree in a scroller. */
129
JScrollPane sp = new JScrollPane();
130
sp.setPreferredSize(new Dimension(300, 300));
131
sp.getViewport().add(tree);
132
133
/* And show it. */
134
panel.setLayout(new BorderLayout());
135
panel.add("Center", sp);
136
panel.add("South", constructOptionsPanel());
137
138
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
139
frame.pack();
140
frame.setVisible(true);
141
}
142
143
/** Constructs a JPanel containing check boxes for the different
144
* options that tree supports. */
145
@SuppressWarnings("serial")
146
private JPanel constructOptionsPanel() {
147
JCheckBox aCheckbox;
148
JPanel retPanel = new JPanel(false);
149
JPanel borderPane = new JPanel(false);
150
151
borderPane.setLayout(new BorderLayout());
152
retPanel.setLayout(new FlowLayout());
153
154
aCheckbox = new JCheckBox("show top level handles");
155
aCheckbox.setSelected(tree.getShowsRootHandles());
156
aCheckbox.addChangeListener(new ShowHandlesChangeListener());
157
retPanel.add(aCheckbox);
158
159
aCheckbox = new JCheckBox("show root");
160
aCheckbox.setSelected(tree.isRootVisible());
161
aCheckbox.addChangeListener(new ShowRootChangeListener());
162
retPanel.add(aCheckbox);
163
164
aCheckbox = new JCheckBox("editable");
165
aCheckbox.setSelected(tree.isEditable());
166
aCheckbox.addChangeListener(new TreeEditableChangeListener());
167
aCheckbox.setToolTipText("Triple click to edit");
168
retPanel.add(aCheckbox);
169
170
borderPane.add(retPanel, BorderLayout.CENTER);
171
172
/* Create a set of radio buttons that dictate what selection should
173
be allowed in the tree. */
174
ButtonGroup group = new ButtonGroup();
175
JPanel buttonPane = new JPanel(false);
176
JRadioButton button;
177
178
buttonPane.setLayout(new FlowLayout());
179
buttonPane.setBorder(new TitledBorder("Selection Mode"));
180
button = new JRadioButton("Single");
181
button.addActionListener(new AbstractAction() {
182
183
@Override
184
public boolean isEnabled() {
185
return true;
186
}
187
188
public void actionPerformed(ActionEvent e) {
189
tree.getSelectionModel().setSelectionMode(
190
TreeSelectionModel.SINGLE_TREE_SELECTION);
191
}
192
});
193
group.add(button);
194
buttonPane.add(button);
195
button = new JRadioButton("Contiguous");
196
button.addActionListener(new AbstractAction() {
197
198
@Override
199
public boolean isEnabled() {
200
return true;
201
}
202
203
public void actionPerformed(ActionEvent e) {
204
tree.getSelectionModel().setSelectionMode(
205
TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
206
}
207
});
208
group.add(button);
209
buttonPane.add(button);
210
button = new JRadioButton("Discontiguous");
211
button.addActionListener(new AbstractAction() {
212
213
@Override
214
public boolean isEnabled() {
215
return true;
216
}
217
218
public void actionPerformed(ActionEvent e) {
219
tree.getSelectionModel().setSelectionMode(
220
TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
221
}
222
});
223
button.setSelected(true);
224
group.add(button);
225
buttonPane.add(button);
226
227
borderPane.add(buttonPane, BorderLayout.SOUTH);
228
229
// NOTE: This will be enabled in a future release.
230
// Create a label and combobox to determine how many clicks are
231
// needed to expand.
232
/*
233
JPanel clickPanel = new JPanel();
234
Object[] values = { "Never", new Integer(1),
235
new Integer(2), new Integer(3) };
236
final JComboBox clickCBox = new JComboBox(values);
237
238
clickPanel.setLayout(new FlowLayout());
239
clickPanel.add(new JLabel("Click count to expand:"));
240
clickCBox.setSelectedIndex(2);
241
clickCBox.addActionListener(new ActionListener() {
242
public void actionPerformed(ActionEvent ae) {
243
Object selItem = clickCBox.getSelectedItem();
244
245
if(selItem instanceof Integer)
246
tree.setToggleClickCount(((Integer)selItem).intValue());
247
else // Don't toggle
248
tree.setToggleClickCount(0);
249
}
250
});
251
clickPanel.add(clickCBox);
252
borderPane.add(clickPanel, BorderLayout.NORTH);
253
*/
254
return borderPane;
255
}
256
257
/** Construct a menu. */
258
private JMenuBar constructMenuBar() {
259
JMenu menu;
260
JMenuBar menuBar = new JMenuBar();
261
JMenuItem menuItem;
262
263
/* Good ol exit. */
264
menu = new JMenu("File");
265
menuBar.add(menu);
266
267
menuItem = menu.add(new JMenuItem("Exit"));
268
menuItem.addActionListener(new ActionListener() {
269
270
public void actionPerformed(ActionEvent e) {
271
System.exit(0);
272
}
273
});
274
275
/* Tree related stuff. */
276
menu = new JMenu("Tree");
277
menuBar.add(menu);
278
279
menuItem = menu.add(new JMenuItem("Add"));
280
menuItem.addActionListener(new AddAction());
281
282
menuItem = menu.add(new JMenuItem("Insert"));
283
menuItem.addActionListener(new InsertAction());
284
285
menuItem = menu.add(new JMenuItem("Reload"));
286
menuItem.addActionListener(new ReloadAction());
287
288
menuItem = menu.add(new JMenuItem("Remove"));
289
menuItem.addActionListener(new RemoveAction());
290
291
return menuBar;
292
}
293
294
/**
295
* Returns the TreeNode instance that is selected in the tree.
296
* If nothing is selected, null is returned.
297
*/
298
protected DefaultMutableTreeNode getSelectedNode() {
299
TreePath selPath = tree.getSelectionPath();
300
301
if (selPath != null) {
302
return (DefaultMutableTreeNode) selPath.getLastPathComponent();
303
}
304
return null;
305
}
306
307
/**
308
* Returns the selected TreePaths in the tree, may return null if
309
* nothing is selected.
310
*/
311
protected TreePath[] getSelectedPaths() {
312
return tree.getSelectionPaths();
313
}
314
315
protected DefaultMutableTreeNode createNewNode(String name) {
316
return new DynamicTreeNode(new SampleData(null, Color.black, name));
317
}
318
319
320
/**
321
* AddAction is used to add a new item after the selected item.
322
*/
323
class AddAction extends Object implements ActionListener {
324
325
/** Number of nodes that have been added. */
326
public int addCount;
327
328
/**
329
* Messaged when the user clicks on the Add menu item.
330
* Determines the selection from the Tree and adds an item
331
* after that. If nothing is selected, an item is added to
332
* the root.
333
*/
334
public void actionPerformed(ActionEvent e) {
335
DefaultMutableTreeNode lastItem = getSelectedNode();
336
DefaultMutableTreeNode parent;
337
338
/* Determine where to create the new node. */
339
if (lastItem != null) {
340
parent = (DefaultMutableTreeNode) lastItem.getParent();
341
if (parent == null) {
342
parent = (DefaultMutableTreeNode) treeModel.getRoot();
343
lastItem = null;
344
}
345
} else {
346
parent = (DefaultMutableTreeNode) treeModel.getRoot();
347
}
348
if (parent == null) {
349
// new root
350
treeModel.setRoot(createNewNode("Added " + Integer.toString(
351
addCount++)));
352
} else {
353
int newIndex;
354
if (lastItem == null) {
355
newIndex = treeModel.getChildCount(parent);
356
} else {
357
newIndex = parent.getIndex(lastItem) + 1;
358
}
359
360
/* Let the treemodel know. */
361
treeModel.insertNodeInto(createNewNode("Added " + Integer.
362
toString(addCount++)),
363
parent, newIndex);
364
}
365
}
366
} // End of SampleTree.AddAction
367
368
369
/**
370
* InsertAction is used to insert a new item before the selected item.
371
*/
372
class InsertAction extends Object implements ActionListener {
373
374
/** Number of nodes that have been added. */
375
public int insertCount;
376
377
/**
378
* Messaged when the user clicks on the Insert menu item.
379
* Determines the selection from the Tree and inserts an item
380
* after that. If nothing is selected, an item is added to
381
* the root.
382
*/
383
public void actionPerformed(ActionEvent e) {
384
DefaultMutableTreeNode lastItem = getSelectedNode();
385
DefaultMutableTreeNode parent;
386
387
/* Determine where to create the new node. */
388
if (lastItem != null) {
389
parent = (DefaultMutableTreeNode) lastItem.getParent();
390
if (parent == null) {
391
parent = (DefaultMutableTreeNode) treeModel.getRoot();
392
lastItem = null;
393
}
394
} else {
395
parent = (DefaultMutableTreeNode) treeModel.getRoot();
396
}
397
if (parent == null) {
398
// new root
399
treeModel.setRoot(createNewNode("Inserted " + Integer.toString(
400
insertCount++)));
401
} else {
402
int newIndex;
403
404
if (lastItem == null) {
405
newIndex = treeModel.getChildCount(parent);
406
} else {
407
newIndex = parent.getIndex(lastItem);
408
}
409
410
/* Let the treemodel know. */
411
treeModel.insertNodeInto(createNewNode("Inserted " + Integer.
412
toString(insertCount++)),
413
parent, newIndex);
414
}
415
}
416
} // End of SampleTree.InsertAction
417
418
419
/**
420
* ReloadAction is used to reload from the selected node. If nothing
421
* is selected, reload is not issued.
422
*/
423
class ReloadAction extends Object implements ActionListener {
424
425
/**
426
* Messaged when the user clicks on the Reload menu item.
427
* Determines the selection from the Tree and asks the treemodel
428
* to reload from that node.
429
*/
430
public void actionPerformed(ActionEvent e) {
431
DefaultMutableTreeNode lastItem = getSelectedNode();
432
433
if (lastItem != null) {
434
treeModel.reload(lastItem);
435
}
436
}
437
} // End of SampleTree.ReloadAction
438
439
440
/**
441
* RemoveAction removes the selected node from the tree. If
442
* The root or nothing is selected nothing is removed.
443
*/
444
class RemoveAction extends Object implements ActionListener {
445
446
/**
447
* Removes the selected item as long as it isn't root.
448
*/
449
public void actionPerformed(ActionEvent e) {
450
TreePath[] selected = getSelectedPaths();
451
452
if (selected != null && selected.length > 0) {
453
TreePath shallowest;
454
455
// The remove process consists of the following steps:
456
// 1 - find the shallowest selected TreePath, the shallowest
457
// path is the path with the smallest number of path
458
// components.
459
// 2 - Find the siblings of this TreePath
460
// 3 - Remove from selected the TreePaths that are descendants
461
// of the paths that are going to be removed. They will
462
// be removed as a result of their ancestors being
463
// removed.
464
// 4 - continue until selected contains only null paths.
465
while ((shallowest = findShallowestPath(selected)) != null) {
466
removeSiblings(shallowest, selected);
467
}
468
}
469
}
470
471
/**
472
* Removes the sibling TreePaths of <code>path</code>, that are
473
* located in <code>paths</code>.
474
*/
475
private void removeSiblings(TreePath path, TreePath[] paths) {
476
// Find the siblings
477
if (path.getPathCount() == 1) {
478
// Special case, set the root to null
479
for (int counter = paths.length - 1; counter >= 0; counter--) {
480
paths[counter] = null;
481
}
482
treeModel.setRoot(null);
483
} else {
484
// Find the siblings of path.
485
TreePath parent = path.getParentPath();
486
MutableTreeNode parentNode = (MutableTreeNode) parent.
487
getLastPathComponent();
488
ArrayList<TreePath> toRemove = new ArrayList<TreePath>();
489
490
// First pass, find paths with a parent TreePath of parent
491
for (int counter = paths.length - 1; counter >= 0; counter--) {
492
if (paths[counter] != null && paths[counter].getParentPath().
493
equals(parent)) {
494
toRemove.add(paths[counter]);
495
paths[counter] = null;
496
}
497
}
498
499
// Second pass, remove any paths that are descendants of the
500
// paths that are going to be removed. These paths are
501
// implicitly removed as a result of removing the paths in
502
// toRemove
503
int rCount = toRemove.size();
504
for (int counter = paths.length - 1; counter >= 0; counter--) {
505
if (paths[counter] != null) {
506
for (int rCounter = rCount - 1; rCounter >= 0;
507
rCounter--) {
508
if ((toRemove.get(rCounter)).isDescendant(
509
paths[counter])) {
510
paths[counter] = null;
511
}
512
}
513
}
514
}
515
516
// Sort the siblings based on position in the model
517
if (rCount > 1) {
518
Collections.sort(toRemove, new PositionComparator());
519
}
520
int[] indices = new int[rCount];
521
Object[] removedNodes = new Object[rCount];
522
for (int counter = rCount - 1; counter >= 0; counter--) {
523
removedNodes[counter] = (toRemove.get(counter)).
524
getLastPathComponent();
525
indices[counter] = treeModel.getIndexOfChild(parentNode,
526
removedNodes[counter]);
527
parentNode.remove(indices[counter]);
528
}
529
treeModel.nodesWereRemoved(parentNode, indices, removedNodes);
530
}
531
}
532
533
/**
534
* Returns the TreePath with the smallest path count in
535
* <code>paths</code>. Will return null if there is no non-null
536
* TreePath is <code>paths</code>.
537
*/
538
private TreePath findShallowestPath(TreePath[] paths) {
539
int shallowest = -1;
540
TreePath shallowestPath = null;
541
542
for (int counter = paths.length - 1; counter >= 0; counter--) {
543
if (paths[counter] != null) {
544
if (shallowest != -1) {
545
if (paths[counter].getPathCount() < shallowest) {
546
shallowest = paths[counter].getPathCount();
547
shallowestPath = paths[counter];
548
if (shallowest == 1) {
549
return shallowestPath;
550
}
551
}
552
} else {
553
shallowestPath = paths[counter];
554
shallowest = paths[counter].getPathCount();
555
}
556
}
557
}
558
return shallowestPath;
559
}
560
561
562
/**
563
* An Comparator that bases the return value on the index of the
564
* passed in objects in the TreeModel.
565
* <p>
566
* This is actually rather expensive, it would be more efficient
567
* to extract the indices and then do the comparision.
568
*/
569
private class PositionComparator implements Comparator<TreePath> {
570
571
public int compare(TreePath p1, TreePath p2) {
572
int p1Index = treeModel.getIndexOfChild(p1.getParentPath().
573
getLastPathComponent(), p1.getLastPathComponent());
574
int p2Index = treeModel.getIndexOfChild(p2.getParentPath().
575
getLastPathComponent(), p2.getLastPathComponent());
576
return p1Index - p2Index;
577
}
578
}
579
} // End of SampleTree.RemoveAction
580
581
582
/**
583
* ShowHandlesChangeListener implements the ChangeListener interface
584
* to toggle the state of showing the handles in the tree.
585
*/
586
class ShowHandlesChangeListener extends Object implements ChangeListener {
587
588
public void stateChanged(ChangeEvent e) {
589
tree.setShowsRootHandles(((JCheckBox) e.getSource()).isSelected());
590
}
591
} // End of class SampleTree.ShowHandlesChangeListener
592
593
594
/**
595
* ShowRootChangeListener implements the ChangeListener interface
596
* to toggle the state of showing the root node in the tree.
597
*/
598
class ShowRootChangeListener extends Object implements ChangeListener {
599
600
public void stateChanged(ChangeEvent e) {
601
tree.setRootVisible(((JCheckBox) e.getSource()).isSelected());
602
}
603
} // End of class SampleTree.ShowRootChangeListener
604
605
606
/**
607
* TreeEditableChangeListener implements the ChangeListener interface
608
* to toggle between allowing editing and now allowing editing in
609
* the tree.
610
*/
611
class TreeEditableChangeListener extends Object implements ChangeListener {
612
613
public void stateChanged(ChangeEvent e) {
614
tree.setEditable(((JCheckBox) e.getSource()).isSelected());
615
}
616
} // End of class SampleTree.TreeEditableChangeListener
617
618
public static void main(String[] args) {
619
try {
620
SwingUtilities.invokeAndWait(new Runnable() {
621
622
@SuppressWarnings(value = "ResultOfObjectAllocationIgnored")
623
public void run() {
624
new SampleTree();
625
}
626
});
627
} catch (InterruptedException ex) {
628
Logger.getLogger(SampleTree.class.getName()).log(Level.SEVERE, null,
629
ex);
630
} catch (InvocationTargetException ex) {
631
Logger.getLogger(SampleTree.class.getName()).log(Level.SEVERE, null,
632
ex);
633
}
634
}
635
}
636
637