Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<idea-plugin version="2">
<id>jp.funnything.offing_harbor</id>
<name>Android Layout ID Converter</name>
<version>1.3</version>
<version>1.4</version>
<vendor email="coding.while.sleep@gmail.com" url="http://flavors.me/funnything">Yosaku Toyama</vendor>

<description><![CDATA[
Expand All @@ -13,6 +13,7 @@
</description>

<change-notes><![CDATA[
1.4: Support '<include />' tag
1.3: Always specify resource id if ButterKnife selected.<br>
1.2: Fix bugs.<br>
1.1: Add ButterKnife support. Add java visibility support. (@zaki50++)<br>
Expand Down Expand Up @@ -44,7 +45,7 @@
<add-to-group anchor="after" group-id="ToolsMenu" relative-to-action="AndroidToolsGroup"/>
<add-to-group anchor="after" group-id="ProjectViewPopupMenu"
relative-to-action="ProjectViewPopupMenuRefactoringGroup"/>
<keyboard-shortcut first-keystroke="meta alt A" keymap="$default"/>
<keyboard-shortcut first-keystroke="ctrl alt A" keymap="$default"/>
</action>
</actions>

Expand Down
37 changes: 1 addition & 36 deletions src/ConvertAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void actionPerformed(AnActionEvent e) {
return;
}

VirtualFile layoutFile = traverseLayoutFileByName(name, e.getProject().getBaseDir(), file, null);
VirtualFile layoutFile = ConvertUtils.traverseLayoutFileByName(name, e.getProject().getBaseDir(), file, null);

if (layoutFile == null) {
showError(String.format("Cannot find layout file for name [%s]", name));
Expand Down Expand Up @@ -76,42 +76,7 @@ private String extractLayoutFileNameFromJavaFile(VirtualFile file) {
}
}

/**
* 基準ファイルから子を優先して探索する
*/
private VirtualFile traverseLayoutFileByName(String name, VirtualFile baseDir, VirtualFile file, VirtualFile traverseFrom) {
VirtualFile parent = file.getParent();

if (!file.isDirectory() && file.getName().equalsIgnoreCase(name + ".xml")) {
if (parent != null && parent.getName().startsWith("layout")) {
VirtualFile grandParent = parent.getParent();
if (grandParent != null && grandParent.getName().equalsIgnoreCase("res")) {
return file;
}
}
}

String traverseFromUrl = traverseFrom != null ? traverseFrom.getUrl() : null;

for (VirtualFile child : file.getChildren()) {
if (!child.getUrl().equals(traverseFromUrl) && !child.getName().startsWith(".")) {
VirtualFile layoutFile = traverseLayoutFileByName(name, baseDir, child, file);
if (layoutFile != null) {
return layoutFile;
}
}
}

if (!file.getUrl().equals(baseDir.getUrl())) {
if (parent != null) {
if (!parent.getUrl().equals(traverseFromUrl)) {
return traverseLayoutFileByName(name, baseDir, parent, file);
}
}
}

return null;
}

private void showError(String content) {
Notifications.Bus.notify(new Notification("OffingHarbor", "OffingHarbor", content, NotificationType.ERROR));
Expand Down
2 changes: 2 additions & 0 deletions src/ConvertConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum Visibility {
public ConvertFormat format;
public Visibility visibility;
public boolean useSmartType;
public boolean detectIncludeNode;

public ConvertConfig() {
// default values
Expand All @@ -31,6 +32,7 @@ public ConvertConfig() {
format = ConvertFormat.PLAIN;
visibility = Visibility.PRIVATE;
useSmartType = false;
detectIncludeNode = true;
}
}

6 changes: 6 additions & 0 deletions src/ConvertConfigDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class ConvertConfigDialog extends DialogWrapper {
private JRadioButton mVisibilityPackagePrivate;
private JRadioButton mVisibilityProtected;
private JCheckBox mSmartTypeCheckBox;
private JCheckBox mIncludeNodeCheckBox;

public ConvertConfigDialog(Project project, VirtualFile layoutFile) {
super(project, true);
Expand Down Expand Up @@ -141,6 +142,10 @@ public void actionPerformed(ActionEvent actionEvent) {
mSmartTypeCheckBox = new JCheckBox("Detect Type by ID");
smartTypeBox.add(mSmartTypeCheckBox);

mIncludeNodeCheckBox = new JCheckBox("Detect 'include' tag");
mIncludeNodeCheckBox.setSelected(true);
smartTypeBox.add(mIncludeNodeCheckBox);

box.add(Box.createHorizontalStrut(5));
box.add(smartTypeBox);

Expand All @@ -155,6 +160,7 @@ private ConvertConfig getConfig() {
config.format = getFormat();
config.visibility = getVisibility();
config.useSmartType = mSmartTypeCheckBox.isSelected();
config.detectIncludeNode = mIncludeNodeCheckBox.isSelected();
return config;
}

Expand Down
67 changes: 44 additions & 23 deletions src/ConvertExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.help.search.ConfigFile;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.awt.datatransfer.StringSelection;
Expand Down Expand Up @@ -133,17 +134,14 @@ private Tree(String name) {
}
}

private ConvertConfig mConfig;
private Project mProject;

public void execute(Project project, VirtualFile file, ConvertConfig config) {
List<AndroidViewInfo> infos;
InputStream is = null;
try {
is = file.getInputStream();
infos = extractViewInfos(is);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Util.closeQuietly(is);
}
mProject = project;
mConfig = config;
infos = extractViewInfos(file);

Tree viewNameTree = config.useSmartType ? prepareViewNames(project) : null;
String javaCode = generateJavaCode(infos, viewNameTree, config);
Expand All @@ -154,41 +152,64 @@ public void execute(Project project, VirtualFile file, ConvertConfig config) {
Notifications.Bus.notify(new Notification("OffingHarbor", "OffingHarbor", "Code is copied to clipboard", NotificationType.INFORMATION), project);
}

private List<AndroidViewInfo> extractViewInfos(InputStream is) {
private List<AndroidViewInfo> extractViewInfos(VirtualFile file) {
List<AndroidViewInfo> infos;
InputStream is = null;

try {
return traverseViewInfos(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is));
is = file.getInputStream();
return traverseViewInfos(file ,DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is));
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Util.closeQuietly(is);
}
}

private List<AndroidViewInfo> traverseViewInfos(Node node) {
private List<AndroidViewInfo> traverseViewInfos(VirtualFile file, Node node) {
List<AndroidViewInfo> infos = Lists.newArrayList();

if (node.getNodeType() == Node.ELEMENT_NODE) {
Node idNode = node.getAttributes().getNamedItem("android:id");

if (idNode != null) {
String value = idNode.getNodeValue();
String[] values = value.split("/");

if (values.length != 2) {
throw new IllegalStateException("android:id value is invalid");
String[] elements = node.getNodeName().split("\\.");
String type = elements[elements.length-1];

if ("include".equals(type) && mConfig.detectIncludeNode) {
Node layoutNode = node.getAttributes().getNamedItem("layout");
if(layoutNode != null){
String value = layoutNode.getNodeValue();
String[] values = value.split("/");

if (values.length != 2) {
throw new IllegalStateException("layout value is invalid");
}
VirtualFile layoutFile = ConvertUtils.traverseLayoutFileByName(values[1], mProject.getBaseDir(), file, null);
if (layoutFile != null) {
infos.addAll(extractViewInfos(layoutFile));
}
}
} else {
Node idNode = node.getAttributes().getNamedItem("android:id");

String[] elements = node.getNodeName().split("\\.");
if (idNode != null) {
String value = idNode.getNodeValue();
String[] values = value.split("/");

infos.add(new AndroidViewInfo(elements[elements.length - 1], values[1]));
if (values.length != 2) {
throw new IllegalStateException("android:id value is invalid");
}

infos.add(new AndroidViewInfo(elements[elements.length - 1], values[1]));
}
}
}

NodeList children = node.getChildNodes();
for (int index = 0; index < children.getLength(); index++) {
infos.addAll(traverseViewInfos(children.item(index)));
infos.addAll(traverseViewInfos(file, children.item(index)));
}

return infos;
Expand Down
43 changes: 43 additions & 0 deletions src/ConvertUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import com.intellij.openapi.vfs.VirtualFile;

/**
* Created by zhouzhiyong on 15-7-24.
*/
public class ConvertUtils {
/**
* 基準ファイルから子を優先して探索する
*/
public static VirtualFile traverseLayoutFileByName(String name, VirtualFile baseDir, VirtualFile file, VirtualFile traverseFrom) {
VirtualFile parent = file.getParent();

if (!file.isDirectory() && file.getName().equalsIgnoreCase(name + ".xml")) {
if (parent != null && parent.getName().startsWith("layout")) {
VirtualFile grandParent = parent.getParent();
if (grandParent != null && grandParent.getName().equalsIgnoreCase("res")) {
return file;
}
}
}

String traverseFromUrl = traverseFrom != null ? traverseFrom.getUrl() : null;

for (VirtualFile child : file.getChildren()) {
if (!child.getUrl().equals(traverseFromUrl) && !child.getName().startsWith(".")) {
VirtualFile layoutFile = traverseLayoutFileByName(name, baseDir, child, file);
if (layoutFile != null) {
return layoutFile;
}
}
}

if (!file.getUrl().equals(baseDir.getUrl())) {
if (parent != null) {
if (!parent.getUrl().equals(traverseFromUrl)) {
return traverseLayoutFileByName(name, baseDir, parent, file);
}
}
}

return null;
}
}