├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── META-INF └── plugin.xml ├── README.md ├── lib └── gson-2.3.1.jar ├── screenshots ├── Beta_Testers.PNG ├── Preview.png ├── Project.PNG ├── Project_Tree_Default.png ├── Project_Tree_Folding.png ├── Project_Tree_Hide_Prefix.png └── Settings.png └── src └── com └── dd ├── ComposeAction.java ├── DirectoryNode.java ├── FoldingNode.java ├── ProjectStructureProvider.java ├── SettingConfigurable.form ├── SettingConfigurable.java ├── Settings.java ├── SettingsManager.java └── Utils.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### Intellij ### 4 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 5 | 6 | *.iml 7 | 8 | ## Directory-based project format: 9 | .idea/ 10 | # if you remove the above rule, at least ignore the following: 11 | 12 | # User-specific stuff: 13 | # .idea/workspace.xml 14 | # .idea/tasks.xml 15 | # .idea/dictionaries 16 | 17 | # Sensitive or high-churn files: 18 | # .idea/dataSources.ids 19 | # .idea/dataSources.xml 20 | # .idea/sqlDataSources.xml 21 | # .idea/dynamic.xml 22 | # .idea/uiDesigner.xml 23 | 24 | # Gradle: 25 | # .idea/gradle.xml 26 | # .idea/libraries 27 | 28 | # Mongo Explorer plugin: 29 | # .idea/mongoSettings.xml 30 | 31 | ## File-based project format: 32 | *.ipr 33 | *.iws 34 | 35 | ## Plugin-specific files: 36 | 37 | # IntelliJ 38 | /out/ 39 | 40 | # mpeltonen/sbt-idea plugin 41 | .idea_modules/ 42 | 43 | # JIRA plugin 44 | atlassian-ide-plugin.xml 45 | 46 | # Crashlytics plugin (for Android Studio and IntelliJ) 47 | com_crashlytics_export_strings.xml 48 | crashlytics.properties 49 | crashlytics-build.properties 50 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1 2 | 3 | 1. Possibility to hide folding prefix 4 | 2. Possibility to set custom folding pattern 5 | 6 | ## 1.0 7 | 8 | Initial release 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Danylyk Dmytro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.dmytrodanylyk.fold 3 | Android File Grouping 4 | 1.0 5 | Dmytro Danylyk 6 | 7 | 9 | It can display your files as a group of different folders only in project structure view. 10 | Note: files will not be physically moved to folders.
11 |
12 | Before decompose.
13 |
14 |       res/
15 |         layout/
16 |           chat_activity.xml
17 |           chat_toolbar.xml
18 |           chat_item.xml
19 |           chat_share_view.xml
20 |           home_activity.xml
21 |           home_toolbar.xml
22 |           home_fragment_sign_in.xml
23 |           home_fragment_sign_up.xml
24 |       
25 |
26 | After decompose.
27 |
28 |       res/
29 |         layout/
30 |           chat/
31 |             chat_activity.xml
32 |             chat_toolbar.xml
33 |             chat_item.xml
34 |             chat_share_view.xml
35 |           home/
36 |             home_activity.xml
37 |             home_toolbar.xml
38 |             home_fragment_sign_in.xml
39 |             home_fragment_sign_up.xml
40 |       
41 |
42 | Naming rules: folder name -> file name part till underscore
43 |
44 | Note The Android project view defines its own structure and does not allow modifying the structure through any extensions.
45 | ]]>
46 | 47 | 50 | 51 | 52 | 53 | 54 | 55 | 57 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Android File Grouping Plugin v1.1 2 | 3 | ![](screenshots/Preview.png) 4 | 5 | ## Description 6 | 7 | This plugin is very helpful in Android Development. It can display your files as a group of different folders in project structure view. 8 | 9 | **Note:** 10 | 11 | - It does NOT move files. 12 | - It does NOT create folders. 13 | 14 | Naming rules: folder name -> file name part till underscore 15 | 16 | Before grouping 17 | 18 | ``` 19 | res/ 20 | layout/ 21 | chat_activity.xml 22 | chat_toolbar.xml 23 | chat_item.xml 24 | chat_share_view.xml 25 | home_activity.xml 26 | home_toolbar.xml 27 | home_fragment_sign_in.xml 28 | home_fragment_sign_up.xml 29 | ``` 30 | 31 | After grouping 32 | 33 | ``` 34 | res/ 35 | layout/ 36 | chat/ 37 | chat_activity.xml 38 | chat_toolbar.xml 39 | chat_item.xml 40 | chat_share_view.xml 41 | home/ 42 | home_activity.xml 43 | home_toolbar.xml 44 | home_fragment_sign_in.xml 45 | home_fragment_sign_up.xml 46 | ``` 47 | 48 | ## Installation & Usage 49 | 50 | Installation 51 | 52 | 1. Download latest Android File Grouping zip file [here](https://github.com/dmytrodanylyk/folding-plugin/releases) 53 | 2. Open AS `Settings`, and select `Plugins` 54 | 3. Click `Install from disk` and choose `Android File Grouping.zip` 55 | 4. Restart 56 | 57 | Usage 58 | 59 | 1. Rick click on layout folder (or any other) 60 | 2. In context menu click Group/Ungroup 61 | 62 | Settings 63 | 64 | Plugin setting can be found by path 'Settings'('Preferences' on Mac Os) -> 'Other Settings' -> 'Folding Plugin' 65 | 66 | ![](screenshots/Settings.png) 67 | 68 | By default, grouping happens by part of filename which situated before first symbol underscore(_). Also, this part 69 | of filename is not hide. Patter for grouping setup as regular expression and can be change 'Setting' -> 'Other Setting' 70 | -> 'Android Folding' -> 'Use custom pattern'. 'Hide Folding Prefix' take potability hide part of filename with 71 | complete with pattern. 72 | 73 | | Default | Folding default | Folding with hide prefix | 74 | | ------------- |:----------------:| :-----------------------:| 75 | | ![](screenshots/Project_Tree_Default.png) | ![](screenshots/Project_Tree_Folding.png) | ![](screenshots/Project_Tree_Hide_Prefix.png) | 76 | 77 | ## Limitations 78 | 79 | The Android project view defines its own structure and does not allow modifying the structure through any extensions. Make sure your are in Project structure view, NOT Android. 80 | 81 | ![](screenshots/Project.PNG) 82 | 83 | ## Credits & License 84 | 85 | Special thanks to [beta testers](screenshots/Beta_Testers.PNG). 86 | 87 | ``` 88 | The MIT License (MIT) 89 | 90 | Copyright (c) 2015 Danylyk Dmytro 91 | 92 | Permission is hereby granted, free of charge, to any person obtaining a copy 93 | of this software and associated documentation files (the "Software"), to deal 94 | in the Software without restriction, including without limitation the rights 95 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 96 | copies of the Software, and to permit persons to whom the Software is 97 | furnished to do so, subject to the following conditions: 98 | 99 | The above copyright notice and this permission notice shall be included in all 100 | copies or substantial portions of the Software. 101 | 102 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 103 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 104 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 105 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 106 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 107 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 108 | SOFTWARE. 109 | ``` 110 | -------------------------------------------------------------------------------- /lib/gson-2.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/lib/gson-2.3.1.jar -------------------------------------------------------------------------------- /screenshots/Beta_Testers.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Beta_Testers.PNG -------------------------------------------------------------------------------- /screenshots/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Preview.png -------------------------------------------------------------------------------- /screenshots/Project.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Project.PNG -------------------------------------------------------------------------------- /screenshots/Project_Tree_Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Project_Tree_Default.png -------------------------------------------------------------------------------- /screenshots/Project_Tree_Folding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Project_Tree_Folding.png -------------------------------------------------------------------------------- /screenshots/Project_Tree_Hide_Prefix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Project_Tree_Hide_Prefix.png -------------------------------------------------------------------------------- /screenshots/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmytrodanylyk/folding-plugin/3efe36f5e524e587ce4265f0d867944319a11b34/screenshots/Settings.png -------------------------------------------------------------------------------- /src/com/dd/ComposeAction.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.intellij.ide.projectView.ProjectView; 4 | import com.intellij.openapi.actionSystem.AnAction; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import com.intellij.openapi.actionSystem.CommonDataKeys; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.psi.PsiDirectory; 9 | 10 | public class ComposeAction extends AnAction { 11 | 12 | private static final String DECOMPOSE = "Ungroup"; 13 | private static final String COMPOSE = "Group"; 14 | 15 | @Override 16 | public void actionPerformed(AnActionEvent actionEvent) { 17 | Object nav = actionEvent.getData(CommonDataKeys.NAVIGATABLE); 18 | if (nav instanceof PsiDirectory) { 19 | PsiDirectory directory = (PsiDirectory) nav; 20 | 21 | String path = directory.getVirtualFile().getPath(); 22 | 23 | if (SettingsManager.isComposed(path)) { 24 | SettingsManager.removeComposedFolder(path); 25 | } else { 26 | SettingsManager.addComposedFolder(path); 27 | } 28 | 29 | Project project = actionEvent.getData(CommonDataKeys.PROJECT); 30 | if (project != null) { 31 | ProjectView.getInstance(project).refresh(); 32 | } 33 | } 34 | } 35 | 36 | @Override 37 | public void update(AnActionEvent actionEvent) { 38 | boolean enabledAndVisible = false; 39 | Project project = actionEvent.getData(CommonDataKeys.PROJECT); 40 | if (project != null) { 41 | Object nav = actionEvent.getData(CommonDataKeys.NAVIGATABLE); 42 | 43 | if (nav instanceof PsiDirectory) { 44 | PsiDirectory directory = (PsiDirectory) nav; 45 | 46 | String path = directory.getVirtualFile().getPath(); 47 | 48 | if (SettingsManager.isComposed(path)) { 49 | actionEvent.getPresentation().setText(DECOMPOSE); 50 | } else { 51 | actionEvent.getPresentation().setText(COMPOSE); 52 | } 53 | 54 | enabledAndVisible = true; 55 | } 56 | } 57 | actionEvent.getPresentation().setEnabledAndVisible(enabledAndVisible); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/com/dd/DirectoryNode.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.ide.projectView.PresentationData; 5 | import com.intellij.ide.projectView.ProjectViewNode; 6 | import com.intellij.ide.projectView.ViewSettings; 7 | import com.intellij.ide.projectView.impl.nodes.PsiFileNode; 8 | import com.intellij.ide.util.PropertiesComponent; 9 | import com.intellij.ide.util.treeView.AbstractTreeNode; 10 | import com.intellij.openapi.project.Project; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import com.intellij.psi.PsiFile; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class DirectoryNode extends ProjectViewNode { 19 | 20 | private final String mName; 21 | private List mChildNodeList; 22 | 23 | protected DirectoryNode(Project project, ViewSettings viewSettings, PsiFile directory, String name) { 24 | super(project, directory, viewSettings); 25 | mName = name; 26 | mChildNodeList = new ArrayList(); 27 | } 28 | 29 | @Override 30 | public boolean contains(@NotNull VirtualFile file) { 31 | for (final AbstractTreeNode childNode : mChildNodeList) { 32 | ProjectViewNode treeNode = (ProjectViewNode) childNode; 33 | if (treeNode.contains(file)) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | public void addChildren(AbstractTreeNode treeNode) { 41 | mChildNodeList.add(treeNode); 42 | } 43 | 44 | public void addAllChildren(List treeNodeList) { 45 | mChildNodeList.addAll(treeNodeList); 46 | } 47 | 48 | @NotNull 49 | @Override 50 | public List getChildren() { 51 | if (PropertiesComponent.getInstance().getBoolean(SettingConfigurable.PREFIX_HIDE, false)) { 52 | final ArrayList abstractTreeNodes = new ArrayList<>(); 53 | for (AbstractTreeNode fileNode : mChildNodeList) { 54 | PsiFile psiFile = (PsiFile) fileNode.getValue(); 55 | final ViewSettings settings = ((PsiFileNode) fileNode).getSettings(); 56 | String shortName = psiFile.getName().substring(mName.length()); 57 | final int beginIndex = shortName.indexOf(ProjectStructureProvider.COMPOSE_BY_CHAR); 58 | if (beginIndex != -1) { 59 | shortName = shortName.substring(beginIndex + 1); 60 | } 61 | abstractTreeNodes.add(new FoldingNode(fileNode.getProject(), psiFile, settings, shortName)); 62 | } 63 | return abstractTreeNodes; 64 | } else { 65 | return mChildNodeList; 66 | } 67 | } 68 | 69 | 70 | @Override 71 | protected void update(PresentationData presentation) { 72 | presentation.setPresentableText(mName); 73 | presentation.setIcon(AllIcons.Nodes.Folder); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/com/dd/FoldingNode.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.intellij.ide.projectView.PresentationData; 4 | import com.intellij.ide.projectView.ViewSettings; 5 | import com.intellij.ide.projectView.impl.nodes.PsiFileNode; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiFile; 8 | 9 | class FoldingNode extends PsiFileNode { 10 | private String mName; 11 | 12 | public FoldingNode(Project project, PsiFile value, ViewSettings viewSettings, String shortName) { 13 | super(project, value, viewSettings); 14 | mName = shortName; 15 | } 16 | 17 | @Override 18 | protected void updateImpl(PresentationData presentationData) { 19 | super.updateImpl(presentationData); 20 | 21 | presentationData.setPresentableText(mName); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/dd/ProjectStructureProvider.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.intellij.ide.projectView.ViewSettings; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.ide.util.treeView.AbstractTreeNode; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.psi.PsiDirectory; 8 | import com.intellij.psi.PsiFile; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Collection; 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | public class ProjectStructureProvider implements com.intellij.ide.projectView.TreeStructureProvider { 20 | 21 | public static final char COMPOSE_BY_CHAR = '_'; 22 | private static final String OTHER_NODE = "other"; 23 | 24 | @Nullable 25 | @Override 26 | public Object getData(Collection collection, String s) { 27 | return null; 28 | } 29 | 30 | @NotNull 31 | @Override 32 | public Collection modify(@NotNull AbstractTreeNode parent, @NotNull Collection children, ViewSettings viewSettings) { 33 | List resultList = new ArrayList<>(); 34 | if (parent.getValue() instanceof PsiDirectory) { 35 | PsiDirectory directory = (PsiDirectory) parent.getValue(); 36 | String path = directory.getVirtualFile().getPath(); 37 | if (SettingsManager.isComposed(path)) { 38 | resultList.addAll(createComposedFiles(children, viewSettings)); 39 | } else { 40 | resultList.addAll(children); 41 | } 42 | } else { 43 | resultList.addAll(children); 44 | } 45 | 46 | return resultList; 47 | } 48 | 49 | @NotNull 50 | private List createComposedFiles(@NotNull Collection fileNodes, ViewSettings viewSettings) { 51 | List resultList = new ArrayList<>(); 52 | Project project = Utils.getCurrentProject(); 53 | if (project != null) { 54 | HashSet composedDirNameSet = new HashSet<>(); 55 | List notComposedFileNodes = new ArrayList<>(); 56 | 57 | final boolean customPrefix = PropertiesComponent.getInstance().getBoolean(SettingConfigurable.PREFIX_CUSTOM_USE, false); 58 | 59 | Pattern pattern = customPrefix ? Pattern.compile(PropertiesComponent.getInstance().getValue(SettingConfigurable.PREFIX_PATTERN, SettingConfigurable.DEFAULT_PATTERN)) : null; 60 | 61 | for (AbstractTreeNode fileNode : fileNodes) { 62 | if (fileNode.getValue() instanceof PsiFile) { 63 | PsiFile psiFile = (PsiFile) fileNode.getValue(); 64 | String fileName = psiFile.getName(); 65 | if (customPrefix) { 66 | Matcher m = pattern.matcher(fileName); 67 | if (m.find()) { 68 | String composedDirName = m.group(0); 69 | composedDirNameSet.add(composedDirName); 70 | } else { 71 | notComposedFileNodes.add(fileNode); 72 | } 73 | } else { 74 | int endIndex = fileName.indexOf(COMPOSE_BY_CHAR); 75 | if (endIndex != -1) { 76 | String composedDirName = fileName.substring(0, endIndex); 77 | composedDirNameSet.add(composedDirName); 78 | } else { 79 | notComposedFileNodes.add(fileNode); 80 | } 81 | } 82 | } 83 | } 84 | 85 | for (String composedDirName : composedDirNameSet) { 86 | List composedFileNodes = filterByDirName(fileNodes, composedDirName); 87 | PsiFile psiFile = (PsiFile) composedFileNodes.get(0).getValue(); 88 | DirectoryNode composedDirNode = new DirectoryNode(project, viewSettings, psiFile, composedDirName); 89 | composedDirNode.addAllChildren(composedFileNodes); 90 | resultList.add(composedDirNode); 91 | } 92 | 93 | if (!notComposedFileNodes.isEmpty()) { 94 | PsiFile psiFile = (PsiFile) notComposedFileNodes.get(0).getValue(); 95 | DirectoryNode composedDirNode = new DirectoryNode(project, viewSettings, psiFile, OTHER_NODE); 96 | composedDirNode.addAllChildren(notComposedFileNodes); 97 | resultList.add(composedDirNode); 98 | } 99 | } 100 | return resultList; 101 | } 102 | 103 | @NotNull 104 | private List filterByDirName(Collection fileNodes, String token) { 105 | List resultList = new ArrayList<>(); 106 | 107 | final boolean customPrefix = PropertiesComponent.getInstance().getBoolean(SettingConfigurable.PREFIX_CUSTOM_USE, false); 108 | 109 | Pattern pattern = customPrefix ? Pattern.compile(PropertiesComponent.getInstance().getValue(SettingConfigurable.PREFIX_PATTERN, SettingConfigurable.DEFAULT_PATTERN)) : null; 110 | 111 | for (AbstractTreeNode fileNode : fileNodes) { 112 | if (fileNode.getValue() instanceof PsiFile) { 113 | PsiFile psiFile = (PsiFile) fileNode.getValue(); 114 | String fileName = psiFile.getName(); 115 | 116 | if (customPrefix) { 117 | Matcher m = pattern.matcher(fileName); 118 | if (m.find()) { 119 | 120 | String composedDirName = m.group(0); 121 | if (composedDirName.equals(token)) { 122 | resultList.add(fileNode); 123 | } 124 | } 125 | } else { 126 | 127 | int endIndex = fileName.indexOf(COMPOSE_BY_CHAR); 128 | if (endIndex != -1) { 129 | String composedDirName = fileName.substring(0, endIndex); 130 | if (composedDirName.equals(token)) { 131 | resultList.add(fileNode); 132 | } 133 | } 134 | } 135 | } 136 | } 137 | 138 | return resultList; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/com/dd/SettingConfigurable.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
49 | -------------------------------------------------------------------------------- /src/com/dd/SettingConfigurable.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.intellij.ide.projectView.ProjectView; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.openapi.options.Configurable; 6 | import com.intellij.openapi.options.ConfigurationException; 7 | import com.intellij.openapi.project.Project; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import javax.swing.*; 12 | import javax.swing.event.DocumentEvent; 13 | import javax.swing.event.DocumentListener; 14 | import java.awt.event.ActionEvent; 15 | import java.awt.event.ActionListener; 16 | 17 | /** 18 | * 19 | * Created by skyrylyuk on 10/15/15. 20 | */ 21 | public class SettingConfigurable implements Configurable { 22 | public static final String PREFIX_PATTERN = "folding_plugin_prefix_pattern"; 23 | public static final String PREFIX_CUSTOM_USE = "folding_plugin_prefix_custom_use"; 24 | public static final String PREFIX_HIDE = "folding_plugin_prefix_hide"; 25 | 26 | public static final String DEFAULT_PATTERN = "[^_]{1,}(?=_)"; 27 | public static final String DEFAULT_PATTERN_DOUBLE = "[^_]{1,}_[^_]{1,}(?=_)"; 28 | 29 | private JPanel mPanel; 30 | private JCheckBox useCustomPatternCheckBox; 31 | private JTextField customPattern; 32 | private JCheckBox hideFoldingPrefix; 33 | private boolean isModified = false; 34 | 35 | @Nls 36 | @Override 37 | public String getDisplayName() { 38 | return "Android Folding"; 39 | } 40 | 41 | @Nullable 42 | @Override 43 | public String getHelpTopic() { 44 | return "null:"; 45 | } 46 | 47 | @Nullable 48 | @Override 49 | public JComponent createComponent() { 50 | 51 | useCustomPatternCheckBox.addActionListener(new ActionListener() { 52 | public void actionPerformed(ActionEvent actionEvent) { 53 | boolean selected = getCheckBoxStatus(actionEvent); 54 | 55 | customPattern.setEnabled(selected); 56 | isModified = true; 57 | } 58 | }); 59 | 60 | customPattern.getDocument().addDocumentListener(new DocumentListener() { 61 | @Override 62 | public void insertUpdate(DocumentEvent e) { 63 | isModified = true; 64 | } 65 | 66 | @Override 67 | public void removeUpdate(DocumentEvent e) { 68 | isModified = true; 69 | } 70 | 71 | @Override 72 | public void changedUpdate(DocumentEvent e) { 73 | isModified = true; 74 | } 75 | }); 76 | 77 | hideFoldingPrefix.addActionListener(new ActionListener() { 78 | public void actionPerformed(ActionEvent actionEvent) { 79 | isModified = true; 80 | } 81 | }); 82 | 83 | reset(); 84 | 85 | return mPanel; 86 | } 87 | 88 | private boolean getCheckBoxStatus(ActionEvent actionEvent) { 89 | AbstractButton abstractButton = (AbstractButton) actionEvent.getSource(); 90 | return abstractButton.getModel().isSelected(); 91 | } 92 | 93 | 94 | @Override 95 | public boolean isModified() { 96 | 97 | return isModified; 98 | } 99 | 100 | @Override 101 | public void apply() throws ConfigurationException { 102 | PropertiesComponent.getInstance().setValue(PREFIX_CUSTOM_USE, Boolean.valueOf(useCustomPatternCheckBox.isSelected()).toString()); 103 | PropertiesComponent.getInstance().setValue(PREFIX_PATTERN, customPattern.getText()); 104 | PropertiesComponent.getInstance().setValue(PREFIX_HIDE, Boolean.valueOf(hideFoldingPrefix.isSelected()).toString()); 105 | 106 | if (isModified) { 107 | Project currentProject = Utils.getCurrentProject(); 108 | 109 | if (currentProject != null) { 110 | ProjectView.getInstance(currentProject).refresh(); 111 | } 112 | } 113 | 114 | isModified = false; 115 | } 116 | 117 | @Override 118 | public void reset() { 119 | final boolean customPrefix = PropertiesComponent.getInstance().getBoolean(PREFIX_CUSTOM_USE, false); 120 | useCustomPatternCheckBox.setSelected(customPrefix); 121 | customPattern.setEnabled(customPrefix); 122 | customPattern.setText(PropertiesComponent.getInstance().getValue(PREFIX_PATTERN, DEFAULT_PATTERN_DOUBLE)); 123 | hideFoldingPrefix.getModel().setSelected(PropertiesComponent.getInstance().getBoolean(PREFIX_HIDE, false)); 124 | } 125 | 126 | @Override 127 | public void disposeUIResources() { 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/com/dd/Settings.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class Settings { 10 | 11 | @SerializedName("DecomposedFolders") 12 | private List mComposedFolders; 13 | 14 | @NotNull 15 | public List getComposedFolders() { 16 | if(mComposedFolders == null) { 17 | mComposedFolders = new ArrayList(); 18 | } 19 | 20 | return mComposedFolders; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/com/dd/SettingsManager.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.google.gson.Gson; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.openapi.project.Project; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class SettingsManager { 9 | 10 | private static final String KEY_SETTINGS = "KEY_COMPOSED_FOLDERS"; 11 | 12 | public static boolean isComposed(@NotNull String folder) { 13 | boolean isFoldingOn = false; 14 | Project currentProject = Utils.getCurrentProject(); 15 | if (currentProject != null) { 16 | Settings settings = getSettings(currentProject); 17 | isFoldingOn = settings.getComposedFolders().contains(folder); 18 | 19 | } 20 | 21 | return isFoldingOn; 22 | } 23 | 24 | public static void addComposedFolder(@NotNull String folder) { 25 | Project currentProject = Utils.getCurrentProject(); 26 | if (currentProject != null) { 27 | Gson gson = new Gson(); 28 | Settings settings = getSettings(currentProject); 29 | settings.getComposedFolders().add(folder); 30 | 31 | PropertiesComponent.getInstance(currentProject).setValue(KEY_SETTINGS, gson.toJson(settings)); 32 | } 33 | 34 | } 35 | 36 | public static void removeComposedFolder(@NotNull String folder) { 37 | Project currentProject = Utils.getCurrentProject(); 38 | if (currentProject != null) { 39 | Gson gson = new Gson(); 40 | Settings settings = getSettings(currentProject); 41 | settings.getComposedFolders().remove(folder); 42 | 43 | PropertiesComponent.getInstance(currentProject).setValue(KEY_SETTINGS, gson.toJson(settings)); 44 | } 45 | } 46 | 47 | @NotNull 48 | private static Settings getSettings(@NotNull Project currentProject) { 49 | Gson gson = new Gson(); 50 | String json = PropertiesComponent.getInstance(currentProject).getValue(KEY_SETTINGS); 51 | Settings settings; 52 | if (json == null) { 53 | settings = new Settings(); 54 | } else { 55 | settings = gson.fromJson(json, Settings.class); 56 | } 57 | 58 | return settings; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/com/dd/Utils.java: -------------------------------------------------------------------------------- 1 | package com.dd; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.project.ProjectManager; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | public final class Utils { 8 | 9 | @Nullable 10 | public static Project getCurrentProject() { 11 | Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); 12 | return openProjects.length > 0 ? openProjects[0] : null; 13 | } 14 | } 15 | --------------------------------------------------------------------------------