use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class CreateResourceFileDialogBase method setupDeviceConfigurationPanel.
protected DeviceConfiguratorPanel setupDeviceConfigurationPanel(final JTextField directoryNameTextField, final TemplateKindCombo resourceTypeCombo, final JBLabel errorLabel) {
return new DeviceConfiguratorPanel() {
@Override
public void applyEditors() {
try {
doApplyEditors();
final FolderConfiguration config = this.getConfiguration();
final CreateTypedResourceFileAction selectedAction = getSelectedAction(resourceTypeCombo);
errorLabel.setText("");
directoryNameTextField.setText("");
if (selectedAction != null) {
final ResourceFolderType resFolderType = selectedAction.getResourceFolderType();
directoryNameTextField.setText(config.getFolderName(resFolderType));
}
} catch (InvalidOptionValueException e) {
errorLabel.setText(new HtmlBuilder().openHtmlBody().coloredText(JBColor.RED, e.getMessage()).closeHtmlBody().getHtml());
directoryNameTextField.setText("");
}
updateOkAction();
}
};
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class ManifestPanel method getHtml.
@NotNull
String getHtml(@NotNull AndroidFacet facet, @NotNull SourceFilePosition sourceFilePosition) {
HtmlBuilder sb = new HtmlBuilder();
describePosition(sb, facet, sourceFilePosition);
return sb.getHtml();
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class ManifestPanel method getErrorRemoveHtml.
@NotNull
private static String getErrorRemoveHtml(@NotNull final AndroidFacet facet, @NotNull String message, @NotNull final SourceFilePosition position, @NotNull HtmlLinkManager htmlLinkManager, @Nullable final VirtualFile currentlyOpenFile) {
/*
Example Input:
ERROR Overlay manifest:package attribute declared at AndroidManifest.xml:3:5-49
value=(com.foo.manifestapplication.debug) has a different value=(com.foo.manifestapplication)
declared in main manifest at AndroidManifest.xml:5:5-43 Suggestion: remove the overlay
declaration at AndroidManifest.xml and place it in the build.gradle: flavorName
{ applicationId = "com.foo.manifestapplication.debug" } AndroidManifest.xml (debug)
*/
HtmlBuilder sb = new HtmlBuilder();
int start = message.indexOf('{');
int end = message.indexOf('}', start + 1);
final String declaration = message.substring(start + 1, end).trim();
if (!declaration.startsWith("applicationId")) {
throw new IllegalArgumentException("unexpected remove suggestion format " + message);
}
final GradleBuildFile buildFile = GradleBuildFile.get(facet.getModule());
Runnable link = null;
if (buildFile != null) {
final String applicationId = declaration.substring(declaration.indexOf('"') + 1, declaration.lastIndexOf('"'));
final File manifestOverlayFile = position.getFile().getSourceFile();
assert manifestOverlayFile != null;
VirtualFile manifestOverlayVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(manifestOverlayFile);
assert manifestOverlayVirtualFile != null;
IdeaSourceProvider sourceProvider = ManifestUtils.findManifestSourceProvider(facet, manifestOverlayVirtualFile);
assert sourceProvider != null;
final String name = sourceProvider.getName();
AndroidModuleModel androidModuleModel = AndroidModuleModel.get(facet.getModule());
assert androidModuleModel != null;
final XmlFile manifestOverlayPsiFile = (XmlFile) PsiManager.getInstance(facet.getModule().getProject()).findFile(manifestOverlayVirtualFile);
assert manifestOverlayPsiFile != null;
if (androidModuleModel.getBuildTypeNames().contains(name)) {
final String packageName = MergedManifest.get(facet).getPackage();
assert packageName != null;
if (applicationId.startsWith(packageName)) {
link = () -> new WriteCommandAction.Simple(facet.getModule().getProject(), "Apply manifest suggestion", buildFile.getPsiFile(), manifestOverlayPsiFile) {
@Override
protected void run() throws Throwable {
if (currentlyOpenFile != null) {
// We mark this action as affecting the currently open file, so the Undo is available in this editor
CommandProcessor.getInstance().addAffectedFiles(facet.getModule().getProject(), currentlyOpenFile);
}
removePackageAttribute(manifestOverlayPsiFile);
final String applicationIdSuffix = applicationId.substring(packageName.length());
@SuppressWarnings("unchecked") List<NamedObject> buildTypes = (List<NamedObject>) buildFile.getValue(BuildFileKey.BUILD_TYPES);
if (buildTypes == null) {
buildTypes = new ArrayList<>();
}
NamedObject buildType = find(buildTypes, name);
if (buildType == null) {
buildType = new NamedObject(name);
buildTypes.add(buildType);
}
buildType.setValue(BuildFileKey.APPLICATION_ID_SUFFIX, applicationIdSuffix);
buildFile.setValue(BuildFileKey.BUILD_TYPES, buildTypes);
GradleSyncInvoker.getInstance().requestProjectSyncAndSourceGeneration(facet.getModule().getProject(), null);
}
}.execute();
}
} else if (androidModuleModel.getProductFlavorNames().contains(name)) {
link = () -> new WriteCommandAction.Simple(facet.getModule().getProject(), "Apply manifest suggestion", buildFile.getPsiFile(), manifestOverlayPsiFile) {
@Override
protected void run() throws Throwable {
if (currentlyOpenFile != null) {
// We mark this action as affecting the currently open file, so the Undo is available in this editor
CommandProcessor.getInstance().addAffectedFiles(facet.getModule().getProject(), currentlyOpenFile);
}
removePackageAttribute(manifestOverlayPsiFile);
@SuppressWarnings("unchecked") List<NamedObject> flavors = (List<NamedObject>) buildFile.getValue(BuildFileKey.FLAVORS);
assert flavors != null;
NamedObject flavor = find(flavors, name);
assert flavor != null;
flavor.setValue(BuildFileKey.APPLICATION_ID, applicationId);
buildFile.setValue(BuildFileKey.FLAVORS, flavors);
GradleSyncInvoker.getInstance().requestProjectSyncAndSourceGeneration(facet.getModule().getProject(), null);
}
}.execute();
}
}
if (link != null) {
sb.addLink(message.substring(0, end + 1), htmlLinkManager.createRunnableLink(link));
sb.add(message.substring(end + 1));
} else {
sb.add(message);
}
return sb.getHtml();
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class SdkQuickfixUtils method createDialog.
@VisibleForTesting
@Nullable
static ModelWizardDialog createDialog(@Nullable Project project, @Nullable Component parent, @Nullable Collection<String> requestedPaths, @Nullable Collection<UpdatablePackage> requestedPackages, @Nullable Collection<LocalPackage> requestedUninstalls, @Nullable AndroidSdkHandler sdkHandler, boolean backgroundable) {
if (sdkHandler == null) {
return null;
}
RepoManager mgr = sdkHandler.getSdkManager(REPO_LOGGER);
if (mgr.getLocalPath() == null) {
String title = "SDK Problem";
String msg = "<html>" + "Your Android SDK is missing or out of date." + "<br>" + "You can configure your SDK via <b>Configure | Project Defaults | Project Structure | SDKs</b></html>";
Messages.showErrorDialog(msg, title);
return null;
}
List<String> unknownPaths = new ArrayList<>();
List<UpdatablePackage> resolvedPackages;
mgr.loadSynchronously(0, new StudioLoggerProgressIndicator(SdkQuickfixUtils.class), new StudioDownloader(), StudioSettingsController.getInstance());
RepositoryPackages packages = mgr.getPackages();
if (requestedPackages == null) {
requestedPackages = new ArrayList<>();
}
requestedPackages.addAll(lookupPaths(requestedPaths, packages, unknownPaths));
try {
resolvedPackages = resolve(requestedPackages, packages);
} catch (PackageResolutionException e) {
Messages.showErrorDialog(e.getMessage(), "Error Resolving Packages");
return null;
}
Set<LocalPackage> resolvedUninstalls = new HashSet<>();
if (requestedUninstalls != null) {
resolvedUninstalls.addAll(requestedUninstalls);
// We don't want to uninstall something required by a package we're installing
resolvedPackages.forEach(updatable -> resolvedUninstalls.remove(updatable.getLocal()));
}
List<UpdatablePackage> unavailableDownloads = Lists.newArrayList();
verifyAvailability(resolvedPackages, unavailableDownloads);
// If there were requests we didn't understand or can't download, show an error.
if (!unknownPaths.isEmpty() || !unavailableDownloads.isEmpty()) {
String title = "Packages Unavailable";
HtmlBuilder builder = new HtmlBuilder();
builder.openHtmlBody().add(String.format("%1$s packages are not available for download!", resolvedPackages.isEmpty() ? "All" : "Some")).newline().newline().add("The following packages are not available:").beginList();
for (UpdatablePackage p : unavailableDownloads) {
builder.listItem().add(p.getRepresentative().getDisplayName());
}
for (String p : unknownPaths) {
builder.listItem().add("Package id " + p);
}
builder.endList().closeHtmlBody();
Messages.showErrorDialog(builder.getHtml(), title);
}
// If everything was removed, don't continue.
if (resolvedPackages.isEmpty() && resolvedUninstalls.isEmpty()) {
return null;
}
List<RemotePackage> installRequests = resolvedPackages.stream().map(UpdatablePackage::getRemote).collect(Collectors.toList());
ModelWizard.Builder wizardBuilder = new ModelWizard.Builder();
wizardBuilder.addStep(new LicenseAgreementStep(new LicenseAgreementModel(mgr.getLocalPath()), installRequests));
InstallSelectedPackagesStep installStep = new InstallSelectedPackagesStep(resolvedPackages, resolvedUninstalls, sdkHandler, backgroundable);
wizardBuilder.addStep(installStep);
ModelWizard wizard = wizardBuilder.build();
String title = "SDK Quickfix Installation";
return new StudioWizardDialogBuilder(wizard, title, parent).setProject(project).setModalityType(DialogWrapper.IdeModalityType.IDE).setCancellationPolicy(ModelWizardDialog.CancellationPolicy.CAN_CANCEL_UNTIL_CAN_FINISH).build();
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class AndroidResourceRenameResourceProcessor method findExistingNameConflicts.
@Override
public void findExistingNameConflicts(final PsiElement originalElement, String newName, final MultiMap<PsiElement, String> conflicts) {
ResourceType type = getResourceType(originalElement);
if (type == null) {
return;
}
PsiElement element = LazyValueResourceElementWrapper.computeLazyElement(originalElement);
if (element == null) {
return;
}
AndroidFacet facet = AndroidFacet.getInstance(element);
if (facet == null) {
return;
}
// First check to see if the new name is conflicting with an existing resource
if (element instanceof PsiFile) {
// The name of a file resource is the name of the file without the extension.
// So when dealing with a file, we must first remove the extension in the name
// before checking if it is already used.
newName = AndroidCommonUtils.getResourceName(type.getName(), newName);
}
AppResourceRepository appResources = AppResourceRepository.getAppResources(facet, true);
if (appResources.hasResourceItem(type, newName)) {
boolean foundElements = false;
PsiField[] resourceFields = AndroidResourceUtil.findResourceFields(facet, type.getName(), newName, true);
String message = String.format("Resource @%1$s/%2$s already exists", type, newName);
if (resourceFields.length > 0) {
// Use find usages to find the actual declaration location such that they can be shown in the conflicts view
AndroidFindUsagesHandlerFactory factory = new AndroidFindUsagesHandlerFactory();
if (factory.canFindUsages(originalElement)) {
FindUsagesHandler handler = factory.createFindUsagesHandler(resourceFields[0], false);
if (handler != null) {
PsiElement[] elements = ArrayUtil.mergeArrays(handler.getPrimaryElements(), handler.getSecondaryElements());
for (PsiElement e : elements) {
if (e instanceof LightElement) {
// AndroidLightField does not work in the conflicts view; UsageInfo throws NPE
continue;
}
conflicts.putValue(e, message);
foundElements = true;
}
}
}
}
if (!foundElements) {
conflicts.putValue(originalElement, message);
}
}
// Next see if the renamed resource is also defined externally, in which case we should ask the
// user if they really want to continue. Despite the name of this method ("findExistingNameConflicts")
// and the dialog used to show the message (ConflictsDialog), this isn't conflict specific; the
// dialog title simply says "Problems Detected" and the label for the text view is "The following
// problems were found". We need to use this because it's the only facility in the rename processor
// which lets us ask the user whether to continue and to have the answer either bail out of the operation
// or to resume.
// See if this is a locally defined resource (you can't rename fields from libraries such as appcompat)
// e.g. ?attr/listPreferredItemHeightSmall
String name = getResourceName(originalElement);
if (name != null) {
Project project = facet.getModule().getProject();
List<ResourceItem> all = appResources.getResourceItem(type, name);
if (all == null) {
all = Collections.emptyList();
}
List<ResourceItem> local = ProjectResourceRepository.getProjectResources(facet, true).getResourceItem(type, name);
if (local == null) {
local = Collections.emptyList();
}
HtmlBuilder builder = null;
if (local.size() == 0 && all.size() > 0) {
builder = new HtmlBuilder(new StringBuilder(300));
builder.add("Resource is also only defined in external libraries and cannot be renamed.");
} else if (local.size() < all.size()) {
// This item is also defined in one of the libraries, not just locally: we can't rename it. Should we
// display some sort of warning?
builder = new HtmlBuilder(new StringBuilder(300));
builder.add("The resource ").beginBold().add(PREFIX_RESOURCE_REF).add(type.getName()).add("/").add(name).endBold();
builder.add(" is defined outside of the project (in one of the libraries) and cannot ");
builder.add("be updated. This can change the behavior of the application.").newline().newline();
builder.add("Are you sure you want to do this?");
}
if (builder != null) {
appendUnhandledReferences(project, facet, all, local, builder);
conflicts.putValue(originalElement, builder.getHtml());
}
}
}
Aggregations