[Translation] Write AndroidStudio plugin (3): setting page

Original text: Write an Android Studio Plugin Part 3: Settings
Author: Marcos Holgado
Translator: Queba Qingmeixi
"Writing AndroidStudio Plugin" series is a blog column officially recommended by IntelliJ IDEA for learning IDE plugin development. I hope it will be helpful to readers in need.

In the second part of this series , we learned how to use Componentpersistent data and use this data to show which new features have been updated after users update our plugin. In today's article, we'll see how to use persistent data to create a settings page.

insert image description here

Remember, you can GitHubfind all the code in this series on , and you can also check out the relevant code for each article on the corresponding branch, where the code for this article is in the Part3branch.

https://github.com/marcosholgado/plugin-medium

What are we going to do?

The purpose of this article is to create a settings page for our plugin , which will be our JIRAfirst step towards bringing it over. There will only be one username and password field on our settings page that our plugin will use to Jira APIinteract with . We also want to be able to have different settings for each projectJira , allowing users to use different accounts based on project (which might be useful).

Step 1: Create a new Project-level Component

In the second part of this series, we've seen what is Component, and also learned that there are three different types of Component. Since we want to be able to set things up differently depending on our Android Studioprofile , the obvious choice is to create a new one .ProjectProject Component

We're basically copying and pasting what we created earlier Component, but removing all unnecessary methods and adding two new fields. These fields will be publicas we will be using them in other parts of the plugin.

Another difference is that this time we implement ProjectComponentthe interface and implement AbstractProjectComponentthe method, which of course also has a parameter in its constructor project. Finally, we have a companion object, pass a projectparameter to get our JiraComponentinstance of. This will allow us to access stored data from elsewhere in the plugin. The new one JiraComponentlooks like this:

@State(name = "JiraConfiguration",
        storages = [Storage(value = "jiraConfiguration.xml")])
class JiraComponent(project: Project? = null) :
        AbstractProjectComponent(project),
        Serializable,
        PersistentStateComponent<JiraComponent> {
    
    

    var username: String = ""
    var password: String = ""

    override fun getState(): JiraComponent? = this

    override fun loadState(state: JiraComponent) =
            XmlSerializerUtil.copyBean(state, this)

    companion object {
    
    
        fun getInstance(project: Project): JiraComponent =
                project.getComponent(JiraComponent::class.java)
    }
}

As we did above, we must also plugin.xmlregister in the file Component:

<project-components>
    <!-- Add your project components here -->
    <component>
        <implementation-class>
            components.JiraComponent
        </implementation-class>
    </component>
</project-components>

Step 2: UI

Before we can take the next step for our setup page, we need to understand how to create on Java Swingby using . There are a number of components that can be used to keep the plugin consistent with other plugins in the plugin. But don't be fooled by the suffix in the name, as you can still convert the code to .IntelliJUIIntelliJSwingUIIDEJavaKotlin

One way to create a new GUI(graphical user interface) is to just right click and go New, then click GUI Form. This action will create a YourName.formnew file named , which will link to another YourName.javafile named . Compared with IntelliJdeveloping according to the given editor mode, I prefer to use my own way and give a hint:

I'll be using Eclipse! (cheers)

I know what you're thinking, but honestly, it's really good. For some reason, IntelliJthe editor is really hard to use, and I can't get the desired effect, but, if you are IntelliJhappy with it, please continue to use it!

Translator's Note : I don't like IDEAthe official editor, but there is no great need to use it Eclipse, because the use Eclipseis only for UI preview.

Back Eclipse, you can download it from here . I currently have Oxygen.3athe version, which is a bit old, but it doesn't matter for what we're going to do. Just create a new project, then right click New, Other, and select JPanel:

The image below is a preview of our settings page:

EclipseNext, we only need to copy the created source code from , and then we can close Eclipseit.

Going back to our plugin, we will now create a settingsnew package called and a JiraSettingsnew class called . Inside that class, we'll create a createComponent()new method called , and finally in that method we can paste Eclipsethe source code we copied from . Then it's time to convert the code to Kotlin, which you should be able to automatically convert successfully to as well Kotlin.

After doing all this, you may encounter some bugs, so fix them.

The first thing we need to fix is ​​that our createComponent()method must return one JComponent, for reasons we'll see next.

Because Eclipsewe're assumed to be in JPanel, you can see a lot of addmethods or methods that don't seem to exist because we're not JPanelin. To fix that, we have to create a new one JPaneland give it some bounds (you can get values ​​from the one Eclipsecreated in JPanel), and since JPanelit's JComponenta subclass of , we'll return it in our method.

Finally, we only need to make some adjustments to compile the whole program, and the final effect should be as follows:

class JiraSettings {
    
    

    private val passwordField = JPasswordField()
    private val txtUsername = JTextField()

    fun createComponent(): JComponent {
    
    

        val mainPanel = JPanel()
        mainPanel.setBounds(0, 0, 452, 120)
        mainPanel.layout = null

        val lblUsername = JLabel("Username")
        lblUsername.setBounds(30, 25, 83, 16)
        mainPanel.add(lblUsername)

        val lblPassword = JLabel("Password")
        lblPassword.setBounds(30, 74, 83, 16)
        mainPanel.add(lblPassword)

        passwordField.setBounds(125, 69, 291, 26)
        mainPanel.add(passwordField)

        txtUsername.setBounds(125, 20, 291, 26)
        mainPanel.add(txtUsername)
        txtUsername.columns = 10

        return mainPanel
    }
}

Step 3: Extensions and Extension points

Before continuing to develop the settings page, we must discuss extensionsand extension points. They will allow your plugin IDEto interact with other plugins or with itself.

  • If you want to extend the functionality of other plugins or plugins IDE, you must declare one or more of them extensions.
  • One or more must be declared if a plugin is to allow other plugins to extend its functionality extension points.

Since we're adding the settings page to the Android Studio, Preferenceswhat we're really going to do is extend Android Studiothe functionality, so we have to declare one extensions.

To do this, we have to implement Configurableand at the same time we have to override some methods.

  • Luckily, we already have createComponent()the method, so we just need to add overridethe keywords.
  • We'll create a boolean, modifiedwith a default value of false, as isModified()the return value of . We'll come back to this later, for now it represents whether the settings page applybutton is enabled or not.
  • We use getDisplayName()the return value of to display the name of the settings page.
  • In applythe method, we need to write Applythe code that will be executed when the user clicks. Quite simply, we Projectget JiraComponentan instance of where the user is, and then UIsave the value in Componentto . Finally, we'll Modifyset to false, at which point we want to disable Applythe button.

The final display effect is as follows:

class JiraSettings(private val project: Project): Configurable {
    
    

    private val passwordField = JPasswordField()
    private val txtUsername = JTextField()

    private var modified = false

    override fun isModified(): Boolean = modified

    override fun getDisplayName(): String = "MyPlugin Jira"

    override fun apply() {
    
    
        val config = JiraComponent.getInstance(project)
        config.username = txtUsername.text
        config.password = String(passwordField.password)

        modified = false
    }

    override fun createComponent(): JComponent {
    
    

        val mainPanel = JPanel()
        mainPanel.setBounds(0, 0, 452, 120)
        mainPanel.layout = null

        val lblUsername = JLabel("Username")
        lblUsername.setBounds(30, 25, 83, 16)
        mainPanel.add(lblUsername)

        val lblPassword = JLabel("Password")
        lblPassword.setBounds(30, 74, 83, 16)
        mainPanel.add(lblPassword)

        passwordField.setBounds(125, 69, 291, 26)
        mainPanel.add(passwordField)

        txtUsername.setBounds(125, 20, 291, 26)
        mainPanel.add(txtUsername)
        txtUsername.columns = 10

        return mainPanel
    }
}

Step 4: Solve the final problem

We're almost done, just a few last questions.

First, we want to save the user's preferences, but we haven't loaded them yet. UIis createComponent()created in the method, so we just need to add the following code before returning to set it with the previously stored value UI:

val config = JiraComponent.getInstance(project)
txtUsername.text = config.username
passwordField.text = config.password

Next, we'll isModified()solve the problem using . falseWe need to somehow change the value from to when the user modifies any value in the settings page true. A very simple way is to implement DocumentListener , which provides us with 3 methods: changeUpdate , insertUpdate and removeUpdate .

In these methods, the only thing we have to do is simply Modifychange the value of to true, which will finally DocumentListenerbe added to our password and username fields.

override fun changedUpdate(e: DocumentEvent?) {
    
    
    modified = true
}

override fun insertUpdate(e: DocumentEvent?) {
    
    
    modified = true
}

override fun removeUpdate(e: DocumentEvent?) {
    
    
    modified = true
}

The final implementation is as follows:

class JiraSettings(private val project: Project): Configurable, DocumentListener {
    
    
    private val passwordField = JPasswordField()
    private val txtUsername = JTextField()
    private var modified = false

    override fun isModified(): Boolean = modified

    override fun getDisplayName(): String = "MyPlugin Jira"

    override fun apply() {
    
    
        val config = JiraComponent.getInstance(project)
        config.username = txtUsername.text
        config.password = String(passwordField.password)
        modified = false
    }

    override fun changedUpdate(e: DocumentEvent?) {
    
    
        modified = true
    }

    override fun insertUpdate(e: DocumentEvent?) {
    
    
        modified = true
    }

    override fun removeUpdate(e: DocumentEvent?) {
    
    
        modified = true
    }

    override fun createComponent(): JComponent {
    
    

        val mainPanel = JPanel()
        mainPanel.setBounds(0, 0, 452, 120)
        mainPanel.layout = null

        val lblUsername = JLabel("Username")
        lblUsername.setBounds(30, 25, 83, 16)
        mainPanel.add(lblUsername)

        val lblPassword = JLabel("Password")
        lblPassword.setBounds(30, 74, 83, 16)
        mainPanel.add(lblPassword)

        passwordField.setBounds(125, 69, 291, 26)
        mainPanel.add(passwordField)

        txtUsername.setBounds(125, 20, 291, 26)
        mainPanel.add(txtUsername)
        txtUsername.columns = 10

        val config = JiraComponent.getInstance(project)
        txtUsername.text = config.username
        passwordField.text = config.password

        passwordField.document?.addDocumentListener(this)
        txtUsername.document?.addDocumentListener(this)

        return mainPanel
    }
}

Step 5: Declare the extension

Same as Component, we also have to plugin.xmldeclare it in the file extension.

<extensions defaultExtensionNs="com.intellij">
    <defaultProjectTypeProvider type="Android"/>
    <projectConfigurable
            instance="settings.JiraSettings">
    </projectConfigurable>
</extensions>

You're done! When debugging or installing a plugin, you can find the new settings page Android Studioby going to . You can also test Preferences/Other Settingswith different ones , and each will remember its own settings.ProjectProject

That's all for part three. In the next article, we'll see how to use these settings to create new Action, Jiramigrated functionality over. In the meantime, if you have any questions, please visit Twitter or leave a comment.


"Writing AndroidStudio Plugins" translation series

About the translator

Hello, I am Qingmei Xun . If you think the article is valuable to you, welcome ❤️, and welcome to follow my blog or GitHub .

If you feel that the article is still lacking, please follow me to urge me to write a better article—what if I improve someday?

Guess you like

Origin blog.csdn.net/mq2553299/article/details/113063459