Skip to content

Commit

Permalink
Finished with v1.0 and uploaded to jetbrains' central repository
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Staff committed Jun 23, 2014
1 parent c3e9f3a commit 2b824e8
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 32 deletions.
64 changes: 32 additions & 32 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
<idea-plugin version="2">
<id>com.yourcompany.unique.plugin.id</id>
<name>Plugin display name here</name>
<version>1.0</version>
<vendor email="[email protected]" url="http://www.yourcompany.com">YourCompany</vendor>

<description><![CDATA[
Enter short description for your plugin here.<br>
<small>most HTML tags may be used</small>
<id>com.jonathonstaff.androidaccessors</id>
<name>AndroidAccessors</name>
<version>1.0</version>
<vendor email="[email protected]" url="http://www.jonathonstaff.com">Jonathon Staff</vendor>

<description><![CDATA[
AndroidAccessors is designed to generate getters and setters for Android projects. It removes leading m's from field names so the external methods are cleaner.<br>
For more details, look at the repo on GitHub:<br>
<a href="https://github.com/jonstaff/AndroidAccessors">https://github.com/jonstaff/AndroidAccessors</a>
]]></description>

<change-notes><![CDATA[
Add change notes here.<br>
<small>most HTML tags may be used</small>
]]>
</change-notes>
<change-notes><![CDATA[
]]>
</change-notes>

<!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
<idea-version since-build="107.105"/>
<!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
<idea-version since-build="107.105"/>

<!-- please see http://confluence.jetbrains.net/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
on how to target different products -->
<!-- uncomment to enable plugin in all products
<depends>com.intellij.modules.lang</depends>
-->
<depends>com.intellij.modules.lang</depends>

<application-components>
<!-- Add your application components here -->
</application-components>
<application-components>
<!-- Add your application components here -->
</application-components>

<project-components>
<!-- Add your project components here -->
</project-components>
<project-components>
<!-- Add your project components here -->
</project-components>

<actions>
<!-- Add your actions here -->
</actions>
<actions>
<action class="com.jonathonstaff.androidaccessors.AccessorAction"
id="com.jonathonstaff.androidaccessors.AccessorAction"
text="AndroidAccessors"
description="Generates proper Android accessors">
<add-to-group group-id="GenerateGroup" anchor="last"/>
</action>
</actions>

<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>
</idea-plugin>
38 changes: 38 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,41 @@ AndroidAccessors
================

IntelliJ/Android Studio plugin to generate proper getters and setters for Android.

Android convention dictates that private member variables be prefaced with an 'm', but the default code generation `Getter and Setter` doesn't handle this so gracefully. AndroidAccessors provides an alternative which generates much cleaner external methods.

Installation
------------

Using IntelliJ's built-in plugin system:

`Preferences > Plugins > Browse repositories... > Search for "AndroidAccessors" > Install Plugin`

or alternatively, download the .jar and install it manually.

Usage
-----

`Code > Generate ...` will bring up the code generation menu — the default keymapping is `ctrl N` on OS X. Select `AndroidAccessors` from the menu and it will display a list of all fields in the current class. Remove any fields you don't need methods for by using the minus sign (-) and click 'OK' to finish.

Developed By
------------

[Jonathon Staff](http://jonathonstaff.com)

License
-------

Copyright 2014 Jonathon Staff

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
54 changes: 54 additions & 0 deletions src/com/jonathonstaff/androidaccessors/AccessorAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.jonathonstaff.androidaccessors;
// Created by jonstaff on 6/23/14.

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;

import java.util.List;

public class AccessorAction extends AnAction {

@Override
public void actionPerformed(AnActionEvent event) {
PsiClass psiClass = getPsiClassFromEvent(event);

GenerateDialog dialog = new GenerateDialog(psiClass);
dialog.show();

if (dialog.isOK()) {
generateAccessors(psiClass, dialog.getSelectedFields());
}
}

private void generateAccessors(final PsiClass psiClass, final List<PsiField> fields) {
new WriteCommandAction.Simple(psiClass.getProject(), psiClass.getContainingFile()) {
@Override
protected void run() throws Throwable {
new CodeGenerator(psiClass, fields).generate();
}
}.execute();
}

private PsiClass getPsiClassFromEvent(AnActionEvent event) {
PsiFile psiFile = event.getData(LangDataKeys.PSI_FILE);
Editor editor = event.getData(PlatformDataKeys.EDITOR);

if (psiFile == null || editor == null) {
return null;
}

int offset = editor.getCaretModel().getOffset();
PsiElement element = psiFile.findElementAt(offset);

return PsiTreeUtil.getParentOfType(element, PsiClass.class);
}
}
90 changes: 90 additions & 0 deletions src/com/jonathonstaff/androidaccessors/CodeGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.jonathonstaff.androidaccessors;
// Created by jonstaff on 6/23/14.

import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;

import java.util.ArrayList;
import java.util.List;

public class CodeGenerator {

private final PsiClass mClass;
private final List<PsiField> mFields;

public CodeGenerator(PsiClass psiClass, List<PsiField> fields) {
mClass = psiClass;
mFields = fields;
}

public void generate() {
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(mClass.getProject());

// TODO: remove old accessors

List<PsiMethod> methods = new ArrayList<PsiMethod>();

for (PsiField field : mFields) {
PsiMethod getter =
elementFactory.createMethodFromText(generateGetterMethod(field), mClass);
PsiMethod setter =
elementFactory.createMethodFromText(generateSetterMethod(field), mClass);
methods.add(getter);
methods.add(setter);
}

JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(mClass.getProject());

for (PsiMethod method : methods) {
styleManager.shortenClassReferences(mClass.add(method));
}
}

private static String generateGetterMethod(PsiField field) {
StringBuilder sb = new StringBuilder("public ");
sb.append(field.getType().getPresentableText());

StringBuilder sb2 = new StringBuilder(field.getName());

// verify that the first character is an 'm' and the second is uppercase
if (sb2.charAt(0) == 'm' && sb2.charAt(1) < 97) {
sb2.deleteCharAt(0);
}
sb2.setCharAt(0, Character.toUpperCase(sb2.charAt(0)));

sb.append(" get").append(sb2.toString()).append("() { return ").append(field.getName())
.append("; }");
return sb.toString();
}

private static String generateSetterMethod(PsiField field) {
StringBuilder sb = new StringBuilder("public void set");
StringBuilder sb2 = new StringBuilder(field.getName());
boolean needsThis = true;

// verify that the first character is an 'm' and the second is uppercase
if (sb2.charAt(0) == 'm' && sb2.charAt(1) < 97) {
sb2.deleteCharAt(0);
needsThis = false;
}
sb2.setCharAt(0, Character.toUpperCase(sb2.charAt(0)));
String paramUpper = sb2.toString();

sb2.setCharAt(0, Character.toLowerCase(sb2.charAt(0)));
String param = sb2.toString();

sb.append(paramUpper).append("(").append(field.getType().getPresentableText()).append(" ")
.append(param).append(") { ");

if (needsThis) {
sb.append("this.");
}
sb.append(field.getName()).append(" = ").append(param).append("; }");

return sb.toString();
}
}
66 changes: 66 additions & 0 deletions src/com/jonathonstaff/androidaccessors/GenerateDialog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.jonathonstaff.androidaccessors;
// Created by jonstaff on 6/23/14.

import com.intellij.ide.util.DefaultPsiElementCellRenderer;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiModifier;
import com.intellij.ui.CollectionListModel;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBList;

import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JPanel;

public class GenerateDialog extends DialogWrapper {

private final LabeledComponent<JPanel> myComponent;
private CollectionListModel<PsiField> myFields;

protected GenerateDialog(PsiClass psiClass) {
super(psiClass.getProject());
setTitle("Select Fields for Android Accessor Generation");

PsiField[] allFields = psiClass.getAllFields();
PsiField[] fields = new PsiField[allFields.length];

int i = 0;

for (PsiField field : allFields) {
if (!field.hasModifierProperty(PsiModifier.STATIC)) {
fields[i++] = field;
}
}

fields = Arrays.copyOfRange(fields, 0, i);

myFields = new CollectionListModel<PsiField>(fields);

JBList fieldList = new JBList(myFields);
fieldList.setCellRenderer(new DefaultPsiElementCellRenderer());
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(fieldList);
decorator.disableAddAction();
JPanel panel = decorator.createPanel();

myComponent = LabeledComponent.create(panel, "Fields for which to generate accessors");

init();
}

@Nullable
@Override
protected JComponent createCenterPanel() {
return myComponent;
}

public List<PsiField> getSelectedFields() {
return myFields.getItems();
}
}

0 comments on commit 2b824e8

Please sign in to comment.