blob: 907e19c74de5ac6b4407e2e316a97396c2b1e584 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package com.android.tools.idea.structure.services.view;
import com.android.tools.idea.structure.EditorPanel;
import com.android.tools.idea.structure.services.DeveloperService;
import com.android.tools.idea.structure.services.DeveloperServiceMetadata;
import com.android.tools.idea.structure.services.ServiceContext;
import com.android.tools.idea.ui.properties.BindingsManager;
import com.android.tools.idea.ui.properties.InvalidationListener;
import com.android.tools.idea.ui.properties.Observable;
import com.android.tools.idea.ui.properties.swing.SelectedProperty;
import com.android.tools.idea.ui.properties.swing.VisibleProperty;
import com.android.utils.HtmlBuilder;
import com.google.common.base.Joiner;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.HyperlinkAdapter;
import com.intellij.ui.HyperlinkLabel;
import com.intellij.util.IconUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import static com.android.tools.idea.ui.properties.expressions.bool.BooleanExpressions.not;
/**
* Panel that provides a UI view onto a {@link DeveloperServiceMetadata}.
*/
public final class DeveloperServicePanel extends EditorPanel {
public static final String DELETE_SERVICE_TITLE = "Confirm Uninstall Service";
public static final String DELETE_SERVICE_MESSAGE =
"You are about to uninstall the %1$s service. This will remove the following dependencies:\n" +
"\n" +
"%2$s\n" +
"\n" +
"This may cause compile errors that you'll have to fix manually. Continue?";
private JPanel myRootPanel;
private JLabel myHeaderLabel;
private JPanel myDetailsPanel;
private JLabel myIcon;
private JPanel myLinksPanel;
private JPanel mySummaryPanel;
private JPanel myOverviewPanel;
private JCheckBox myEnabledCheckbox;
private JPanel myCheckboxBorder;
@NotNull private DeveloperService myService;
@NotNull private BindingsManager myBindings = new BindingsManager();
public DeveloperServicePanel(@NotNull DeveloperService service) {
super(new BorderLayout());
myService = service;
ServiceContext context = service.getContext();
DeveloperServiceMetadata developerServiceMetadata = service.getMetadata();
initializeHeaderPanel(developerServiceMetadata);
myDetailsPanel.add(service.getPanel());
initializeFooterPanel(developerServiceMetadata);
final SelectedProperty enabledCheckboxSelected = new SelectedProperty(myEnabledCheckbox);
myBindings.bind(new VisibleProperty(myDetailsPanel), enabledCheckboxSelected.and(not(context.installed())));
// This definition might be modified from the user interacting with the service earlier but not
// yet committing to install it.
myBindings.bind(new SelectedProperty(myEnabledCheckbox), context.installed().or(context.modified()));
enabledCheckboxSelected.addListener(new InvalidationListener() {
@Override
protected void onInvalidated(@NotNull Observable sender) {
if (enabledCheckboxSelected.get()) {
// User just selected a service which was previous uninstalled
myService.getContext().beginEditing();
}
else {
if (myService.getContext().installed().get()) {
// User just deselected a service which was previous installed
String message = String.format(DELETE_SERVICE_MESSAGE, myService.getMetadata().getName(),
Joiner.on('\n').join(myService.getMetadata().getDependencies()));
int answer = Messages.showYesNoDialog(myService.getModule().getProject(), message, DELETE_SERVICE_TITLE, null);
if (answer == Messages.YES) {
myService.uninstall();
}
else {
enabledCheckboxSelected.set(true);
}
}
else {
// User just deselected a service they were editing but hadn't installed yet
myService.getContext().cancelEditing();
}
}
}
});
add(myRootPanel);
}
private void initializeHeaderPanel(@NotNull DeveloperServiceMetadata developerServiceMetadata) {
HtmlBuilder htmlBuilder = new HtmlBuilder();
htmlBuilder.openHtmlBody();
htmlBuilder.addBold(developerServiceMetadata.getName()).newline();
htmlBuilder.add(developerServiceMetadata.getDescription());
htmlBuilder.closeHtmlBody();
myHeaderLabel.setText(htmlBuilder.getHtml());
myIcon.setIcon(IconUtil.toSize(developerServiceMetadata.getIcon(), myIcon.getWidth(), myIcon.getHeight()));
URI learnMoreLink = developerServiceMetadata.getLearnMoreLink();
if (learnMoreLink != null) {
addToLinkPanel("Learn More", learnMoreLink);
}
URI apiLink = developerServiceMetadata.getApiLink();
if (apiLink != null) {
addToLinkPanel("API Documentation", apiLink);
}
}
private void initializeFooterPanel(@NotNull DeveloperServiceMetadata developerServiceMetadata) {
boolean panelHasContent = false;
JPanel verticalFlowPanel = new JPanel();
verticalFlowPanel.setLayout(new BoxLayout(verticalFlowPanel, BoxLayout.PAGE_AXIS));
verticalFlowPanel.add(Box.createRigidArea(new Dimension(0, 30)));
final HtmlBuilder htmlBuilder = new HtmlBuilder();
htmlBuilder.openHtmlBody();
htmlBuilder.add("Enabling this service will...");
htmlBuilder.beginList();
List<String> dependencies = developerServiceMetadata.getDependencies();
if (!dependencies.isEmpty()) {
htmlBuilder.listItem().add("Add dependencies: ").addItalic(Joiner.on(", ").join(dependencies));
panelHasContent = true;
}
List<String> permissions = developerServiceMetadata.getPermissions();
if (!permissions.isEmpty()) {
htmlBuilder.listItem().add("Add permissions: ").addItalic(Joiner.on(", ").join(permissions));
panelHasContent = true;
}
List<String> modifiedFiles = developerServiceMetadata.getModifiedFiles();
if (!modifiedFiles.isEmpty()) {
htmlBuilder.listItem().add("Create/modify files: ").addItalic(Joiner.on(", ").join(modifiedFiles));
panelHasContent = true;
}
htmlBuilder.endList();
htmlBuilder.closeHtmlBody();
if (panelHasContent) {
verticalFlowPanel.add(new JLabel(htmlBuilder.getHtml()));
mySummaryPanel.add(verticalFlowPanel);
}
}
private void addToLinkPanel(@NotNull String text, @NotNull final URI uri) {
HyperlinkLabel hyperlinkLabel = new HyperlinkLabel(text);
hyperlinkLabel.addHyperlinkListener(new HyperlinkAdapter() {
@Override
protected void hyperlinkActivated(HyperlinkEvent e) {
try {
Desktop.getDesktop().browse(uri);
}
catch (IOException ex) {
// Don't care
}
}
});
// Setting the padding on myLinksPanel puts in ugly leading space, so we instead space links
// apart using invisible rigid areas instead.
if (myLinksPanel.getComponentCount() > 0) {
myLinksPanel.add(Box.createRigidArea(new Dimension(10, 0)));
}
myLinksPanel.add(hyperlinkLabel);
}
@Override
public void apply() {
myService.getContext().finishEditing();
if (!isModified()) {
return;
}
myService.install();
}
@Override
public boolean isModified() {
return myService.getContext().modified().get();
}
public void dispose() {
myDetailsPanel.removeAll();
}
}