From 44ace5ba8d6e26c80c7ee5586ee514912f88c301 Mon Sep 17 00:00:00 2001 From: Anna Bulenkova Date: Thu, 8 Jan 2015 13:53:02 +0100 Subject: [PATCH] [code] custom project view pane - filtering images --- project_view_pane/META-INF/plugin.xml | 1 + .../sample/pane/ImagesProjectNode.java | 171 ++++++++++++++++++ .../sample/pane/ImagesProjectViewPane.java | 109 +++++++++++ 3 files changed, 281 insertions(+) create mode 100644 project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectNode.java create mode 100644 project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectViewPane.java diff --git a/project_view_pane/META-INF/plugin.xml b/project_view_pane/META-INF/plugin.xml index 758cf6ae1..9121c0ff1 100644 --- a/project_view_pane/META-INF/plugin.xml +++ b/project_view_pane/META-INF/plugin.xml @@ -13,6 +13,7 @@ com.intellij.modules.lang + diff --git a/project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectNode.java b/project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectNode.java new file mode 100644 index 000000000..43ea9f838 --- /dev/null +++ b/project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectNode.java @@ -0,0 +1,171 @@ +package org.jetbrains.plugins.sample.pane; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ProjectView; +import com.intellij.ide.projectView.impl.ProjectViewImpl; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileAdapter; +import com.intellij.openapi.vfs.VirtualFileEvent; +import com.intellij.psi.search.FilenameIndex; +import com.intellij.util.Alarm; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.*; + +/** + * @author Anna Bulenkova + */ +public class ImagesProjectNode extends AbstractTreeNode { + private static final Key> IMAGES_PROJECT_DIRS = Key.create("images.files.or.directories"); + + public ImagesProjectNode(final Project project) { + super(project, project.getBaseDir()); + scanImages(project); + + subscribeToVFS(project); + } + + public ImagesProjectNode(Project project, VirtualFile file) { + super(project, file); + } + + private void scanImages(Project project) { + addAllByExt(project, "png"); + addAllByExt(project, "jpg"); + } + + private void addAllByExt(Project project, String ext) { + final Set imagesFiles = getImagesFiles(project); + final VirtualFile projectDir = project.getBaseDir(); + for (VirtualFile file : FilenameIndex.getAllFilesByExt(project, ext)) { + while (file != null && !file.equals(projectDir)) { + imagesFiles.add(file); + file = file.getParent(); + } + } + } + + @NotNull + private Set getImagesFiles(Project project) { + Set files = project.getUserData(IMAGES_PROJECT_DIRS); + if (files == null) { + files = new HashSet(); + project.putUserData(IMAGES_PROJECT_DIRS, files); + } + return files; + } + + @Override + protected VirtualFile getVirtualFile() { + return getValue(); + } + + @NotNull + @Override + public Collection getChildren() { + final List files = new ArrayList(0); + for (VirtualFile file : getValue().getChildren()) { + if (getImagesFiles(myProject).contains(file)) { + files.add(file); + } + } + if (files.isEmpty()) return Collections.emptyList(); + final List nodes = new ArrayList(files.size()); + final boolean alwaysOnTop = ((ProjectViewImpl) ProjectView.getInstance(myProject)).isFoldersAlwaysOnTop(); + Collections.sort(files, new Comparator() { + @Override + public int compare(VirtualFile o1, VirtualFile o2) { + if (alwaysOnTop) { + final boolean d1 = o1.isDirectory(); + final boolean d2 = o2.isDirectory(); + if (d1 && !d2) return -1; + if (!d1 && d2) return 1; + } + + return StringUtil.naturalCompare(o1.getName(), o2.getName()); + } + }); + for (VirtualFile file : files) { + nodes.add(new ImagesProjectNode(myProject, file)); + } + return nodes; + } + + @Override + protected void update(PresentationData data) { + data.setIcon(getValue().isDirectory() ? AllIcons.Nodes.Folder : getValue().getFileType().getIcon()); + data.setPresentableText(getValue().getName()); + } + + + @Override + public boolean canNavigate() { + return !getValue().isDirectory(); + } + + @Override + public boolean canNavigateToSource() { + return canNavigate(); + } + + @Override + public void navigate(boolean requestFocus) { + FileEditorManager.getInstance(myProject).openFile(getValue(), false); + } + + private void subscribeToVFS(final Project project) { + final Alarm alarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, project); + LocalFileSystem.getInstance().addVirtualFileListener(new VirtualFileAdapter() { + { + final VirtualFileAdapter me = this; + Disposer.register(project, new Disposable() { + @Override + public void dispose() { + LocalFileSystem.getInstance().removeVirtualFileListener(me); + } + }); + } + + @Override + public void fileCreated(@NotNull VirtualFileEvent event) { + handle(event); + } + + @Override + public void fileDeleted(@NotNull VirtualFileEvent event) { + handle(event); + } + + void handle(VirtualFileEvent event) { + final String filename = event.getFileName().toLowerCase(); + if (filename.endsWith(".png") || filename.endsWith(".jpg")) { + alarm.cancelAllRequests(); + alarm.addRequest(new Runnable() { + public void run() { + getImagesFiles(project).clear(); + scanImages(project); + //noinspection SSBasedInspection + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ProjectView.getInstance(myProject).getProjectViewPaneById(ImagesProjectViewPane.ID).updateFromRoot(true); + } + }); + } + }, 1000); + } + } + }); + } +} + diff --git a/project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectViewPane.java b/project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectViewPane.java new file mode 100644 index 000000000..7d5d902ed --- /dev/null +++ b/project_view_pane/src/org/jetbrains/plugins/sample/pane/ImagesProjectViewPane.java @@ -0,0 +1,109 @@ +package org.jetbrains.plugins.sample.pane; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.SelectInTarget; +import com.intellij.ide.impl.ProjectViewSelectInTarget; +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.AbstractProjectViewPSIPane; +import com.intellij.ide.projectView.impl.ProjectAbstractTreeStructureBase; +import com.intellij.ide.projectView.impl.ProjectTreeStructure; +import com.intellij.ide.projectView.impl.ProjectViewTree; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.ide.util.treeView.AbstractTreeUpdater; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +/** + * @author Anna Bulenkova + */ +public class ImagesProjectViewPane extends AbstractProjectViewPSIPane { + public static final String ID = "IMAGES"; + + protected ImagesProjectViewPane(Project project) { + super(project); + } + + @Override + public String getTitle() { + return "Images"; + } + + @Override + public javax.swing.Icon getIcon() { + return AllIcons.FileTypes.Custom; + } + + @NotNull + @Override + public String getId() { + return ID; + } + + @Override + public int getWeight() { + return 10; + } + + @Override + public SelectInTarget createSelectInTarget() { + return new ProjectViewSelectInTarget(myProject) { + + @Override + public String toString() { + return "images"; + } + + @Nullable + @Override + public String getMinorViewId() { + return "images"; + } + + @Override + public float getWeight() { + return 10; + } + }; + } + + @Override + protected ProjectAbstractTreeStructureBase createStructure() { + return new ProjectTreeStructure(myProject, ID) { + @Override + protected AbstractTreeNode createRoot(Project project, ViewSettings settings) { + return new ImagesProjectNode(project); + } + + @Override + public Object[] getChildElements(Object element) { + return super.getChildElements(element); + } + }; + } + + @Override + protected ProjectViewTree createTree(DefaultTreeModel model) { + return new ProjectViewTree(myProject, model) { + @Override + public DefaultMutableTreeNode getSelectedNode() { + return ImagesProjectViewPane.this.getSelectedNode(); + } + + @Override + public boolean isRootVisible() { + return true; + } + }; + } + + @Override + protected AbstractTreeUpdater createTreeUpdater(AbstractTreeBuilder builder) { + return new AbstractTreeUpdater(builder); + } +} +