mirror of https://github.com/weisJ/darklaf.git
weisj
3 years ago
8 changed files with 0 additions and 1187 deletions
@ -1,207 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.InvalidPathException; |
||||
import java.nio.file.Path; |
||||
import java.util.Arrays; |
||||
import java.util.Objects; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
import java.util.stream.Stream; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.filechooser.FileSystemView; |
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class FileNode implements Comparable<FileNode> { |
||||
|
||||
private static final AtomicBoolean LOCKED = new AtomicBoolean(false); |
||||
private final Object lock = new Object(); |
||||
private volatile File file; |
||||
private final Path path; |
||||
private final String pathName; |
||||
private boolean empty; |
||||
private boolean valid; |
||||
private Icon icon; |
||||
|
||||
public FileNode(final File file, final Path path) { |
||||
this.file = file; |
||||
this.path = path; |
||||
this.pathName = this.file != null ? this.file.getAbsolutePath() : null; |
||||
if (this.file == null) { |
||||
this.file = getFile(); |
||||
} |
||||
} |
||||
|
||||
public void invalidate() { |
||||
valid = false; |
||||
icon = null; |
||||
} |
||||
|
||||
protected boolean validateEmptyFlag(final boolean showHiddenFiles) { |
||||
if (!valid && path != null) { |
||||
try (Stream<Path> s = Files.list(path)) { |
||||
empty = s.filter(Files::isReadable).noneMatch(p -> showHiddenFiles || !isHidden(p)); |
||||
valid = true; |
||||
} catch (final IOException ignored) { |
||||
} |
||||
} |
||||
return valid; |
||||
} |
||||
|
||||
public static FileNode fromPath(final Path path) { |
||||
return new FileNode(null, path); |
||||
} |
||||
|
||||
public static FileNode fromFile(final File file) { |
||||
return new FileNode(file, toPath(file)); |
||||
} |
||||
|
||||
private static Path toPath(final File file) { |
||||
try { |
||||
return file.toPath(); |
||||
} catch (final InvalidPathException e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public boolean isDirectory() { |
||||
if (path != null) return Files.isDirectory(path); |
||||
return file != null && file.isDirectory(); |
||||
} |
||||
|
||||
public boolean exists() { |
||||
if (path != null) return Files.exists(path); |
||||
return file != null && file.exists(); |
||||
} |
||||
|
||||
public boolean notExists() { |
||||
if (path != null) return Files.notExists(path); |
||||
return file == null || !file.exists(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object o) { |
||||
if (this == o) return true; |
||||
if (o == null || getClass() != o.getClass()) return false; |
||||
FileNode on = (FileNode) o; |
||||
if (this.path != null && on.path != null) return path.equals(on.path); |
||||
return Objects.equals(pathName, ((FileNode) o).pathName); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
if (path != null) return path.hashCode(); |
||||
return Objects.hashCode(pathName); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return path != null ? path.toString() : file != null ? pathName : "null node"; |
||||
} |
||||
|
||||
@Override |
||||
public int compareTo(final FileNode o) { |
||||
if (o == null) return -1; |
||||
if (path != null && o.path != null) { |
||||
return path.compareTo(o.path); |
||||
} |
||||
return pathName.compareTo(o.pathName); |
||||
} |
||||
|
||||
public boolean isHidden() { |
||||
boolean hidden; |
||||
hidden = isHidden(path); |
||||
if (file != null) { |
||||
hidden = hidden || file.isHidden(); |
||||
} |
||||
return hidden; |
||||
} |
||||
|
||||
private static boolean isHidden(final Path path) { |
||||
if (path != null) { |
||||
try { |
||||
return Files.isHidden(path); |
||||
} catch (final IOException ignored) { |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public boolean isEmpty(final boolean showHiddenFiles) { |
||||
if (path != null && validateEmptyFlag(showHiddenFiles)) { |
||||
return empty; |
||||
} |
||||
return file == null || !file.isDirectory(); |
||||
} |
||||
|
||||
public boolean isReadable() { |
||||
if (path != null) return Files.isReadable(path); |
||||
return file != null && file.canRead(); |
||||
} |
||||
|
||||
public Stream<FileNode> list(final FileTreeModel model) throws IOException { |
||||
Stream<FileNode> stream; |
||||
if (path != null) { |
||||
stream = Files.list(path).map(FileNode::fromPath); |
||||
} else if (file != null) { |
||||
LOCKED.set(true); |
||||
File[] files = model.fsv.getFiles(file, !model.showHiddenFiles); |
||||
stream = Arrays.stream(files).map(FileNode::fromFile).onClose(() -> LOCKED.set(false)); |
||||
} else { |
||||
stream = Stream.empty(); |
||||
} |
||||
return stream; |
||||
} |
||||
|
||||
public Icon getSystemIcon(final FileSystemView fsv) { |
||||
if (icon == null) { |
||||
icon = fsv.getSystemIcon(getFile()); |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
public String getSystemDisplayName(final FileSystemView fsv) { |
||||
File f = getFile(); |
||||
if (f == null) return path != null ? String.valueOf(path.getFileName()) : ""; |
||||
return fsv.getSystemDisplayName(f); |
||||
} |
||||
|
||||
public Path getPath() { |
||||
return path; |
||||
} |
||||
|
||||
public File getFile() { |
||||
synchronized (lock) { |
||||
if (file == null && this.path != null && !LOCKED.get()) { |
||||
file = path.toFile(); |
||||
} |
||||
return file; |
||||
} |
||||
} |
||||
} |
@ -1,98 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.io.File; |
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.filechooser.FileSystemView; |
||||
import javax.swing.tree.TreeModel; |
||||
import javax.swing.tree.TreePath; |
||||
|
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class FileTree extends JTree { |
||||
|
||||
public FileTree() { |
||||
this((File[]) null); |
||||
} |
||||
|
||||
public FileTree(final File... rootFile) { |
||||
this(false, rootFile); |
||||
} |
||||
|
||||
public FileTree(final boolean showHiddenFiles, final File... rootFiles) { |
||||
FileSystemView fileSystemView = FileSystemView.getFileSystemView(); |
||||
setFileTreeModel(createModel(fileSystemView, showHiddenFiles, rootFiles)); |
||||
setCellRenderer(new FileTreeCellRenderer(fileSystemView)); |
||||
setRootVisible(false); |
||||
} |
||||
|
||||
protected FileTreeModel createModel(final FileSystemView fsv, final boolean showHiddenFiles, |
||||
final File... rootFiles) { |
||||
return new FileTreeModel(fsv, showHiddenFiles, rootFiles); |
||||
} |
||||
|
||||
public boolean isShowHiddenFiles() { |
||||
return getModel().isShowHiddenFiles(); |
||||
} |
||||
|
||||
public void setShowHiddenFiles(final boolean showHiddenFiles) { |
||||
getModel().setShowHiddenFiles(showHiddenFiles); |
||||
} |
||||
|
||||
@Override |
||||
public FileTreeModel getModel() { |
||||
return (FileTreeModel) super.getModel(); |
||||
} |
||||
|
||||
public void setFileTreeModel(final FileTreeModel fileTreeModel) { |
||||
super.setModel(fileTreeModel); |
||||
} |
||||
|
||||
@Override |
||||
public void setModel(final TreeModel newModel) {} |
||||
|
||||
public void reload() { |
||||
getModel().reload(); |
||||
} |
||||
|
||||
public FileNode getSelectedFile() { |
||||
TreePath path = getSelectionPath(); |
||||
if (path == null) return null; |
||||
return ((FileTreeNode) path.getLastPathComponent()).getFile(); |
||||
} |
||||
|
||||
public List<FileNode> getSelectedFiles() { |
||||
TreePath[] paths = getSelectionPaths(); |
||||
if (paths == null) return Collections.emptyList(); |
||||
return Arrays.stream(getSelectionPaths()).map(TreePath::getLastPathComponent).map(FileTreeNode.class::cast) |
||||
.map(FileTreeNode::getFile).collect(Collectors.toList()); |
||||
} |
||||
} |
@ -1,70 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.awt.*; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.filechooser.FileSystemView; |
||||
import javax.swing.tree.DefaultTreeCellRenderer; |
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class FileTreeCellRenderer extends DefaultTreeCellRenderer { |
||||
|
||||
private final FileSystemView fsv; |
||||
protected Icon fileIcon; |
||||
protected Icon directoryIcon; |
||||
|
||||
public FileTreeCellRenderer(final FileSystemView fileSystemView) { |
||||
this.fsv = fileSystemView; |
||||
} |
||||
|
||||
@Override |
||||
public void updateUI() { |
||||
super.updateUI(); |
||||
fileIcon = UIManager.getIcon("FileView.fileIcon"); |
||||
directoryIcon = UIManager.getIcon("FileView.directoryIcon"); |
||||
} |
||||
|
||||
@Override |
||||
public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean selected, |
||||
final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { |
||||
FileTreeNode node = ((FileTreeNode) value); |
||||
FileNode f = node.getFile(); |
||||
if (f != null) { |
||||
setIcon(getFileIcon(f)); |
||||
setText(f.getSystemDisplayName(fsv)); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
protected Icon getFileIcon(final FileNode f) { |
||||
Icon icon = f.getSystemIcon(fsv); |
||||
if (icon == null && f.exists()) { |
||||
icon = f.isDirectory() ? directoryIcon : fileIcon; |
||||
} |
||||
return icon; |
||||
} |
||||
} |
@ -1,103 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.io.File; |
||||
import java.nio.file.Path; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import javax.swing.filechooser.FileSystemView; |
||||
import javax.swing.tree.DefaultTreeModel; |
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class FileTreeModel extends DefaultTreeModel { |
||||
|
||||
protected final FileSystemView fsv; |
||||
protected boolean showHiddenFiles; |
||||
|
||||
public FileTreeModel(final FileSystemView fileSystemView) { |
||||
this(fileSystemView, false, (Path[]) null); |
||||
} |
||||
|
||||
public FileTreeModel(final FileSystemView fileSystemView, final boolean showHiddenFiles, final File... roots) { |
||||
super(null); |
||||
init(); |
||||
this.showHiddenFiles = showHiddenFiles; |
||||
this.fsv = fileSystemView; |
||||
this.root = createRoot(roots); |
||||
} |
||||
|
||||
public FileTreeModel(final FileSystemView fileSystemView, final boolean showHiddenFiles, final Path... roots) { |
||||
super(null); |
||||
init(); |
||||
this.showHiddenFiles = showHiddenFiles; |
||||
this.fsv = fileSystemView; |
||||
this.root = createRoot(roots); |
||||
} |
||||
|
||||
protected void init() {} |
||||
|
||||
protected FileTreeNode createRoot(final Path... roots) { |
||||
List<FileNode> nodes = |
||||
roots != null ? Arrays.stream(roots).map(FileNode::fromPath).collect(Collectors.toList()) : null; |
||||
return new FileTreeNode.RootNode(this, nodes); |
||||
} |
||||
|
||||
protected FileTreeNode createRoot(final File... roots) { |
||||
List<FileNode> nodes = |
||||
roots != null ? Arrays.stream(roots).map(FileNode::fromFile).collect(Collectors.toList()) : null; |
||||
return new FileTreeNode.RootNode(this, nodes); |
||||
} |
||||
|
||||
@Override |
||||
public void reload() { |
||||
getRoot().reload(); |
||||
} |
||||
|
||||
@Override |
||||
public FileTreeNode getRoot() { |
||||
return (FileTreeNode) super.getRoot(); |
||||
} |
||||
|
||||
public void setShowHiddenFiles(final boolean showHiddenFiles) { |
||||
if (showHiddenFiles == this.showHiddenFiles) return; |
||||
this.showHiddenFiles = showHiddenFiles; |
||||
reload(); |
||||
} |
||||
|
||||
public boolean isShowHiddenFiles() { |
||||
return showHiddenFiles; |
||||
} |
||||
|
||||
protected FileTreeNode createNode(final FileTreeNode parent, final FileNode fileNode) { |
||||
return new FileTreeNode(parent, fileNode, this); |
||||
} |
||||
|
||||
protected void register(final FileTreeNode node) {} |
||||
|
||||
protected void unregister(final FileTreeNode node) {} |
||||
} |
@ -1,356 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.file.FileSystems; |
||||
import java.nio.file.WatchKey; |
||||
import java.util.*; |
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
import java.util.concurrent.atomic.AtomicReference; |
||||
import java.util.function.Consumer; |
||||
import java.util.stream.Stream; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.tree.TreeNode; |
||||
|
||||
import com.github.weisj.darklaf.util.Lambdas; |
||||
import com.github.weisj.darklaf.util.StreamUtil; |
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class FileTreeNode implements TreeNode, Comparable<FileTreeNode> { |
||||
|
||||
protected final FileTreeNode parent; |
||||
protected final FileTreeModel model; |
||||
protected final FileNode fileNode; |
||||
protected AtomicInteger taskCount = new AtomicInteger(); |
||||
protected AtomicReference<List<FileTreeNode>> children; |
||||
protected WatchKey watchKey; |
||||
|
||||
public FileTreeNode(final FileTreeNode parent, final FileNode fileNode, final FileTreeModel model) { |
||||
if (fileNode == null) throw new IllegalArgumentException("File node is null"); |
||||
this.model = model; |
||||
this.fileNode = fileNode; |
||||
this.parent = parent; |
||||
this.children = new AtomicReference<>(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object o) { |
||||
if (this == o) return true; |
||||
if (o == null || getClass() != o.getClass()) return false; |
||||
FileTreeNode that = (FileTreeNode) o; |
||||
return Objects.equals(fileNode, that.fileNode); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return fileNode.hashCode(); |
||||
} |
||||
|
||||
public FileNode getFile() { |
||||
return fileNode; |
||||
} |
||||
|
||||
private int addSorted(final List<FileTreeNode> nodes, final FileTreeNode node) { |
||||
int index = Collections.binarySearch(nodes, node); |
||||
if (index < 0) index = ~index; |
||||
nodes.add(index, node); |
||||
model.register(node); |
||||
return index; |
||||
} |
||||
|
||||
private int remove(final List<FileTreeNode> nodes, final FileTreeNode node) { |
||||
int index = nodes.indexOf(node); |
||||
if (index >= 0) { |
||||
nodes.remove(node); |
||||
model.unregister(node); |
||||
} |
||||
return index; |
||||
} |
||||
|
||||
public void reload() { |
||||
reload(Integer.MAX_VALUE); |
||||
} |
||||
|
||||
protected void reload(final int depth) { |
||||
if (depth < 0) return; |
||||
if (children.get() == null) return; |
||||
List<FileTreeNode> fileList = children.get(); |
||||
this.<ReloadOp>doInBackground(pub -> { |
||||
this.traverseChildren(s -> Stream.concat(s.map(this::toNode), fileList.stream()).map(n -> { |
||||
if (n.fileNode.notExists()) { |
||||
return ReloadOp.remove(n, remove(fileList, n)); |
||||
} else { |
||||
if (model.showHiddenFiles) { |
||||
if (!fileList.contains(n)) { |
||||
return ReloadOp.add(n, addSorted(fileList, n)); |
||||
} |
||||
} else { |
||||
if (n.fileNode.isHidden()) { |
||||
return ReloadOp.remove(n, remove(fileList, n)); |
||||
} else if (!fileList.contains(n)) { |
||||
return ReloadOp.add(n, addSorted(fileList, n)); |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
}).forEach(pub)); |
||||
}, chunk -> { |
||||
for (ReloadOp op : chunk) { |
||||
if (op != null && op.index >= 0) { |
||||
switch (op.type) { |
||||
case ADD: |
||||
model.nodesWereInserted(FileTreeNode.this, new int[] {op.index}); |
||||
break; |
||||
case REMOVE: |
||||
model.nodesWereRemoved(FileTreeNode.this, new int[] {op.index}, new Object[] {op.node}); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
}, () -> { |
||||
fileNode.invalidate(); |
||||
if (depth > 0) fileList.forEach(n -> n.reload(depth - 1)); |
||||
}); |
||||
} |
||||
|
||||
private List<FileTreeNode> getChildren() { |
||||
return children.updateAndGet(list -> { |
||||
if (list != null) { |
||||
return list; |
||||
} |
||||
List<FileTreeNode> fileList = Collections.synchronizedList(new ArrayList<>()); |
||||
this.<Integer>doInBackground(pub -> { |
||||
traverseChildren(s -> { |
||||
s.filter(p -> model.showHiddenFiles || !p.isHidden()).map(this::toNode).sorted() |
||||
.map(n -> addSorted(fileList, n)).forEach(pub); |
||||
}); |
||||
}, chunks -> { |
||||
int[] indices = chunks.stream().mapToInt(Integer::intValue).toArray(); |
||||
model.nodesWereInserted(FileTreeNode.this, indices); |
||||
}, () -> model.nodeChanged(FileTreeNode.this)); |
||||
return fileList; |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return fileNode.toString(); |
||||
} |
||||
|
||||
protected FileTreeNode toNode(final FileNode fileNode) { |
||||
return model.createNode(FileTreeNode.this, fileNode); |
||||
} |
||||
|
||||
protected void traverseChildren(final Consumer<Stream<FileNode>> consumer) { |
||||
if (fileNode.isDirectory()) { |
||||
try (Stream<FileNode> files = fileNode.list(model)) { |
||||
consumer.accept(files.filter(FileNode::isReadable)); |
||||
} catch (final IOException ignored) { |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected <T> void doInBackground(final Consumer<Consumer<T>> task, final Consumer<List<T>> processor) { |
||||
doInBackground(task, processor, Lambdas.DO_NOTHING); |
||||
} |
||||
|
||||
protected <T> void doInBackground(final Consumer<Consumer<T>> task, final Consumer<List<T>> processor, |
||||
final Runnable doneTask) { |
||||
taskCount.getAndIncrement(); |
||||
SwingWorker<Void, T> worker = new SwingWorker<Void, T>() { |
||||
@Override |
||||
public Void doInBackground() { |
||||
task.accept(this::publish); |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
protected void process(final List<T> chunks) { |
||||
processor.accept(chunks); |
||||
} |
||||
|
||||
@Override |
||||
protected void done() { |
||||
doneTask.run(); |
||||
taskCount.getAndDecrement(); |
||||
} |
||||
}; |
||||
worker.execute(); |
||||
} |
||||
|
||||
@Override |
||||
public TreeNode getChildAt(final int childIndex) { |
||||
return getChildren().get(childIndex); |
||||
} |
||||
|
||||
@Override |
||||
public int getChildCount() { |
||||
return getChildren().size(); |
||||
} |
||||
|
||||
@Override |
||||
public TreeNode getParent() { |
||||
return parent; |
||||
} |
||||
|
||||
@Override |
||||
public int getIndex(final TreeNode node) { |
||||
if (node == null) { |
||||
throw new IllegalArgumentException("argument is null"); |
||||
} |
||||
if (!isNodeChild(node)) { |
||||
return -1; |
||||
} |
||||
return getChildren().indexOf(node); |
||||
} |
||||
|
||||
@Override |
||||
public boolean getAllowsChildren() { |
||||
return fileNode.isDirectory(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isLeaf() { |
||||
if (!fileNode.isDirectory()) return true; |
||||
if (children.get() != null && !isBusy()) { |
||||
return children.get().size() == 0; |
||||
} |
||||
return fileNode.isEmpty(model.showHiddenFiles); |
||||
} |
||||
|
||||
@Override |
||||
public Enumeration<? extends TreeNode> children() { |
||||
return Collections.enumeration(children.get()); |
||||
} |
||||
|
||||
public boolean isNodeChild(final TreeNode aNode) { |
||||
if (aNode == null) return false; |
||||
return (aNode.getParent() == this); |
||||
} |
||||
|
||||
@Override |
||||
public int compareTo(final FileTreeNode o) { |
||||
if (o == null) return -1; |
||||
boolean thisDir = fileNode.isDirectory(); |
||||
boolean oDir = fileNode.isDirectory(); |
||||
if (thisDir == oDir) { |
||||
return fileNode.compareTo(o.fileNode); |
||||
} else { |
||||
return thisDir ? -1 : 1; |
||||
} |
||||
} |
||||
|
||||
public boolean isBusy() { |
||||
return taskCount.get() > 0; |
||||
} |
||||
|
||||
public static class RootNode extends FileTreeNode { |
||||
|
||||
private final List<FileNode> rootPaths; |
||||
|
||||
public RootNode(final FileTreeModel model, final List<FileNode> rootPaths) { |
||||
super(null, new FileNode(null, null), model); |
||||
this.rootPaths = rootPaths != null ? rootPaths : Collections.emptyList(); |
||||
init(); |
||||
} |
||||
|
||||
protected Stream<FileNode> createInitialDirectories() { |
||||
return rootPaths.size() > 0 ? rootPaths.stream() |
||||
: StreamUtil.iterableAsStream(FileSystems.getDefault().getRootDirectories()) |
||||
.map(FileNode::fromPath); |
||||
} |
||||
|
||||
protected void init() { |
||||
List<FileTreeNode> nodes = new ArrayList<>(); |
||||
createInitialDirectories().forEach(p -> { |
||||
FileTreeNode node = model.createNode(RootNode.this, p); |
||||
model.register(node); |
||||
nodes.add(node); |
||||
}); |
||||
children.set(nodes); |
||||
} |
||||
|
||||
@Override |
||||
protected void reload(final int depth) { |
||||
if (depth < 0) return; |
||||
List<FileTreeNode> nodes = children.get(); |
||||
createInitialDirectories().forEach(p -> { |
||||
FileTreeNode node = model.createNode(this, p); |
||||
if (!nodes.contains(node)) { |
||||
model.register(node); |
||||
nodes.add(node); |
||||
} |
||||
}); |
||||
nodes.removeIf(n -> { |
||||
if (n.fileNode.notExists()) { |
||||
model.unregister(n); |
||||
return true; |
||||
} |
||||
return false; |
||||
}); |
||||
if (depth > 0) children.get().forEach(n -> n.reload(depth - 1)); |
||||
fileNode.invalidate(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isLeaf() { |
||||
return children.get().size() == 0; |
||||
} |
||||
|
||||
@Override |
||||
public boolean getAllowsChildren() { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
private static class ReloadOp { |
||||
|
||||
private final Type type; |
||||
private final FileTreeNode node; |
||||
private final int index; |
||||
|
||||
private ReloadOp(final Type type, final FileTreeNode node, final int index) { |
||||
this.type = type; |
||||
this.node = node; |
||||
this.index = index; |
||||
} |
||||
|
||||
private static ReloadOp add(final FileTreeNode n, final int index) { |
||||
return new ReloadOp(Type.ADD, n, index); |
||||
} |
||||
|
||||
private static ReloadOp remove(final FileTreeNode n, final int index) { |
||||
return new ReloadOp(Type.REMOVE, n, index); |
||||
} |
||||
|
||||
private enum Type { |
||||
ADD, |
||||
REMOVE |
||||
} |
||||
|
||||
} |
||||
} |
@ -1,84 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.io.File; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.filechooser.FileSystemView; |
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class WatchFileTree extends FileTree { |
||||
|
||||
public WatchFileTree() { |
||||
super(); |
||||
} |
||||
|
||||
public WatchFileTree(final File... rootFiles) { |
||||
super(rootFiles); |
||||
} |
||||
|
||||
public WatchFileTree(final boolean showHiddenFiles, final File... rootFiles) { |
||||
super(showHiddenFiles, rootFiles); |
||||
} |
||||
|
||||
@Override |
||||
protected FileTreeModel createModel(final FileSystemView fsv, final boolean showHiddenFiles, |
||||
final File... rootFiles) { |
||||
return new WatchFileTreeModel(fsv, showHiddenFiles, rootFiles); |
||||
} |
||||
|
||||
@Override |
||||
public void setFileTreeModel(final FileTreeModel fileTreeModel) { |
||||
if (getModel() == fileTreeModel) return; |
||||
if (getModel() instanceof WatchFileTreeModel) { |
||||
((WatchFileTreeModel) getModel()).stopWatching(); |
||||
} |
||||
if (isVisible() && fileTreeModel instanceof WatchFileTreeModel) { |
||||
((WatchFileTreeModel) fileTreeModel).startWatching(); |
||||
} |
||||
super.setFileTreeModel(fileTreeModel); |
||||
} |
||||
|
||||
@Override |
||||
public void addNotify() { |
||||
super.addNotify(); |
||||
SwingUtilities.invokeLater(() -> { |
||||
if (getModel() instanceof WatchFileTreeModel) { |
||||
((WatchFileTreeModel) getModel()).startWatching(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public void removeNotify() { |
||||
super.removeNotify(); |
||||
SwingUtilities.invokeLater(() -> { |
||||
if (getModel() instanceof WatchFileTreeModel) { |
||||
((WatchFileTreeModel) getModel()).stopWatching(); |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -1,186 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.components.filetree; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.file.*; |
||||
import java.util.*; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
import java.util.concurrent.ScheduledFuture; |
||||
import java.util.concurrent.ScheduledThreadPoolExecutor; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
import java.util.logging.Logger; |
||||
|
||||
import javax.swing.filechooser.FileSystemView; |
||||
|
||||
import com.github.weisj.darklaf.util.LogUtil; |
||||
|
||||
/** |
||||
* @deprecated {@link FileTree} will be moved to https://github.com/weisJ/swing-dsl
|
||||
*/ |
||||
@Deprecated |
||||
public class WatchFileTreeModel extends FileTreeModel { |
||||
|
||||
private static final Logger LOGGER = LogUtil.getLogger(WatchFileTreeModel.class); |
||||
private static final ScheduledExecutorService scheduler = createScheduler(); |
||||
private WatchService watchService; |
||||
private Map<Watchable, FileTreeNode> nodeMap; |
||||
private Object lock; |
||||
|
||||
private final AtomicBoolean isScheduled = new AtomicBoolean(false); |
||||
private ScheduledFuture<?> watchTask; |
||||
|
||||
private static WatchService createWatchService() { |
||||
WatchService ws = null; |
||||
try { |
||||
ws = FileSystems.getDefault().newWatchService(); |
||||
} catch (final IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return ws; |
||||
} |
||||
|
||||
private static ScheduledExecutorService createScheduler() { |
||||
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, r -> { |
||||
final Thread thread = new Thread(r, "File Tree Watch Thread"); |
||||
thread.setDaemon(true); |
||||
thread.setPriority(Thread.MIN_PRIORITY); |
||||
return thread; |
||||
}); |
||||
executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); |
||||
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); |
||||
return executor; |
||||
} |
||||
|
||||
public WatchFileTreeModel(final FileSystemView fileSystemView) { |
||||
super(fileSystemView); |
||||
} |
||||
|
||||
public WatchFileTreeModel(final FileSystemView fileSystemView, final boolean showHiddenFiles, final File... roots) { |
||||
super(fileSystemView, showHiddenFiles, roots); |
||||
} |
||||
|
||||
public WatchFileTreeModel(final FileSystemView fileSystemView, final boolean showHiddenFiles, final Path... roots) { |
||||
super(fileSystemView, showHiddenFiles, roots); |
||||
} |
||||
|
||||
@Override |
||||
protected void init() { |
||||
lock = new Object(); |
||||
watchService = createWatchService(); |
||||
nodeMap = Collections.synchronizedMap(new HashMap<>()); |
||||
} |
||||
|
||||
private Object getLock() { |
||||
return lock; |
||||
} |
||||
|
||||
protected WatchService getWatchService() { |
||||
return watchService; |
||||
} |
||||
|
||||
protected Map<Watchable, FileTreeNode> getNodeMap() { |
||||
return nodeMap; |
||||
} |
||||
|
||||
public void startWatching() { |
||||
if (watchTask != null) return; |
||||
isScheduled.set(true); |
||||
watchTask = scheduler.schedule(this::watch, 0, TimeUnit.SECONDS); |
||||
} |
||||
|
||||
public void stopWatching() { |
||||
if (watchTask != null) { |
||||
isScheduled.set(false); |
||||
watchTask.cancel(true); |
||||
watchTask = null; |
||||
} |
||||
} |
||||
|
||||
private void watch() { |
||||
while (isScheduled.get()) { |
||||
WatchKey key; |
||||
try { |
||||
key = watchService.take(); |
||||
} catch (final InterruptedException x) { |
||||
x.printStackTrace(); |
||||
return; |
||||
} |
||||
|
||||
FileTreeNode parent = getNodeMap().get(key.watchable()); |
||||
if (parent != null) { |
||||
LOGGER.fine(() -> "Event for \"" + parent + "\""); |
||||
if (parent.parent != null) { |
||||
parent.parent.reload(1); |
||||
} else { |
||||
parent.reload(0); |
||||
} |
||||
} |
||||
|
||||
List<WatchEvent<?>> watchEventList = key.pollEvents(); |
||||
for (WatchEvent<?> event : watchEventList) { |
||||
WatchEvent.Kind<?> kind = event.kind(); |
||||
|
||||
Path path = (Path) event.context(); |
||||
if (kind == StandardWatchEventKinds.OVERFLOW) { |
||||
continue; |
||||
} |
||||
LOGGER.finer("Event Type " + kind.name()); |
||||
FileTreeNode node = getNodeMap().get(((Path) key.watchable()).resolve(path)); |
||||
if (node != null) { |
||||
LOGGER.finer(() -> "Affected node \"" + node + "\""); |
||||
node.reload(0); |
||||
} |
||||
} |
||||
|
||||
key.reset(); |
||||
} |
||||
} |
||||
|
||||
protected void register(final FileTreeNode node) { |
||||
synchronized (getLock()) { |
||||
WatchService ws = getWatchService(); |
||||
if (ws == null || !node.fileNode.isDirectory()) return; |
||||
Path path = node.fileNode.getPath(); |
||||
if (path == null) return; |
||||
if (getNodeMap().containsKey(path)) return; |
||||
try { |
||||
LOGGER.finer(() -> "Register watch service for \"" + node + "\""); |
||||
node.watchKey = path.register(ws, StandardWatchEventKinds.ENTRY_CREATE, |
||||
StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); |
||||
getNodeMap().put(path, node); |
||||
} catch (final IOException ignored) { |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected void unregister(final FileTreeNode node) { |
||||
synchronized (getLock()) { |
||||
if (node.watchKey == null) return; |
||||
LOGGER.finer(() -> "Unregister watch service for \"" + node + "\""); |
||||
getNodeMap().remove(node.fileNode.getPath()); |
||||
node.watchKey.cancel(); |
||||
} |
||||
} |
||||
} |
@ -1,83 +0,0 @@
|
||||
/* |
||||
* MIT License |
||||
* |
||||
* Copyright (c) 2021 Jannis Weis |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and |
||||
* associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, |
||||
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
||||
* furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included in all copies or |
||||
* substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT |
||||
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*/ |
||||
package com.github.weisj.darklaf.ui.tree; |
||||
|
||||
import java.awt.*; |
||||
import java.io.File; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.filechooser.FileSystemView; |
||||
|
||||
import com.github.weisj.darklaf.components.OverlayScrollPane; |
||||
import com.github.weisj.darklaf.components.filetree.FileTree; |
||||
import com.github.weisj.darklaf.core.test.DelicateDemo; |
||||
import com.github.weisj.darklaf.ui.DemoPanel; |
||||
import com.github.weisj.darklaf.ui.button.ButtonConstants; |
||||
import com.github.weisj.darklaf.ui.demo.BaseComponentDemo; |
||||
import com.github.weisj.darklaf.ui.demo.DemoExecutor; |
||||
|
||||
@DelicateDemo(reason = "Deprecated") |
||||
public class FileTreeDemo extends BaseComponentDemo { |
||||
|
||||
public static void main(final String[] args) { |
||||
DemoExecutor.showDemo(new FileTreeDemo()); |
||||
} |
||||
|
||||
@Override |
||||
public JComponent createComponent() { |
||||
FileSystemView fsv = FileSystemView.getFileSystemView(); |
||||
File[] rootFiles = fsv.getFiles(fsv.getRoots()[0], true); |
||||
FileTree tree = new FileTree(false, rootFiles); |
||||
DemoPanel panel = new DemoPanel(new OverlayScrollPane(tree), new BorderLayout(), 0); |
||||
JPanel controlPanel = panel.addControls(); |
||||
controlPanel.add(new JCheckBox("Show hidden files") { |
||||
{ |
||||
setSelected(tree.isShowHiddenFiles()); |
||||
addActionListener(e -> tree.setShowHiddenFiles(isSelected())); |
||||
} |
||||
}); |
||||
controlPanel.add(new JButton("Reload") { |
||||
{ |
||||
putClientProperty(ButtonConstants.KEY_THIN, true); |
||||
addActionListener(e -> tree.reload()); |
||||
} |
||||
}); |
||||
controlPanel = panel.addControls(); |
||||
controlPanel.add(new JLabel(DarkTreeUI.KEY_LINE_STYLE + ":", JLabel.RIGHT)); |
||||
controlPanel.add(new JComboBox<String>() { |
||||
{ |
||||
addItem(DarkTreeUI.STYLE_LINE); |
||||
addItem(DarkTreeUI.STYLE_DASHED); |
||||
addItem(DarkTreeUI.STYLE_NONE); |
||||
setSelectedItem(DarkTreeUI.STYLE_LINE); |
||||
addItemListener(e -> tree.putClientProperty(DarkTreeUI.KEY_LINE_STYLE, e.getItem())); |
||||
} |
||||
}); |
||||
return panel; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "File Tree Demo"; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue