1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.ui; 18 19 20 import static com.android.ide.common.resources.ResourceResolver.PREFIX_ANDROID_RESOURCE_REF; 21 import static com.android.ide.common.resources.ResourceResolver.PREFIX_RESOURCE_REF; 22 23 import com.android.annotations.NonNull; 24 import com.android.ide.common.rendering.api.ResourceValue; 25 import com.android.ide.common.resources.ResourceItem; 26 import com.android.ide.common.resources.ResourceRepository; 27 import com.android.ide.common.resources.ResourceResolver; 28 import com.android.ide.eclipse.adt.AdtPlugin; 29 import com.android.ide.eclipse.adt.AdtUtils; 30 import com.android.ide.eclipse.adt.internal.assetstudio.OpenCreateAssetSetWizardAction; 31 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; 32 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; 33 import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringRefactoring; 34 import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringWizard; 35 import com.android.ide.eclipse.adt.internal.resources.ResourceHelper; 36 import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; 37 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; 38 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; 39 import com.android.resources.ResourceType; 40 import com.android.util.Pair; 41 42 import org.eclipse.core.resources.IFile; 43 import org.eclipse.core.resources.IProject; 44 import org.eclipse.core.resources.IResource; 45 import org.eclipse.core.runtime.IStatus; 46 import org.eclipse.core.runtime.Status; 47 import org.eclipse.jface.dialogs.IDialogConstants; 48 import org.eclipse.jface.dialogs.IInputValidator; 49 import org.eclipse.jface.dialogs.InputDialog; 50 import org.eclipse.jface.text.IRegion; 51 import org.eclipse.jface.window.Window; 52 import org.eclipse.ltk.ui.refactoring.RefactoringWizard; 53 import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; 54 import org.eclipse.swt.SWT; 55 import org.eclipse.swt.events.ModifyEvent; 56 import org.eclipse.swt.events.ModifyListener; 57 import org.eclipse.swt.events.SelectionAdapter; 58 import org.eclipse.swt.events.SelectionEvent; 59 import org.eclipse.swt.layout.GridData; 60 import org.eclipse.swt.layout.GridLayout; 61 import org.eclipse.swt.widgets.Button; 62 import org.eclipse.swt.widgets.Composite; 63 import org.eclipse.swt.widgets.Control; 64 import org.eclipse.swt.widgets.Event; 65 import org.eclipse.swt.widgets.Label; 66 import org.eclipse.swt.widgets.Listener; 67 import org.eclipse.swt.widgets.Shell; 68 import org.eclipse.swt.widgets.Text; 69 import org.eclipse.ui.IWorkbench; 70 import org.eclipse.ui.PlatformUI; 71 import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog; 72 import org.eclipse.ui.dialogs.SelectionStatusDialog; 73 74 import java.util.Arrays; 75 import java.util.Collection; 76 import java.util.Collections; 77 import java.util.List; 78 import java.util.Locale; 79 import java.util.regex.Matcher; 80 import java.util.regex.Pattern; 81 82 /** 83 * A dialog to let the user select a resource based on a resource type. 84 */ 85 public class ResourceChooser extends AbstractElementListSelectionDialog implements ModifyListener { 86 /** The return code from the dialog for the user choosing "Clear" */ 87 public static final int CLEAR_RETURN_CODE = -5; 88 /** The dialog button ID for the user choosing "Clear" */ 89 private static final int CLEAR_BUTTON_ID = CLEAR_RETURN_CODE; 90 91 private Pattern mProjectResourcePattern; 92 private ResourceType mResourceType; 93 private final ResourceRepository mProjectResources; 94 private final ResourceRepository mFrameworkResources; 95 private Pattern mSystemResourcePattern; 96 private Button mProjectButton; 97 private Button mSystemButton; 98 private Button mNewButton; 99 private String mCurrentResource; 100 private final IProject mProject; 101 private IInputValidator mInputValidator; 102 103 /** Helper object used to draw previews for drawables and colors. */ 104 private ResourcePreviewHelper mPreviewHelper; 105 106 /** 107 * Textfield for editing the actual returned value, updated when selection 108 * changes. Only shown if {@link #mShowValueText} is true. 109 */ 110 private Text mEditValueText; 111 112 /** 113 * Whether the {@link #mEditValueText} textfield should be shown when the dialog is created. 114 */ 115 private boolean mShowValueText; 116 117 /** 118 * Flag indicating whether it's the first time {@link #handleSelectionChanged()} is called. 119 * This is used to filter out the first selection event, always called by the superclass 120 * when the widget is created, to distinguish between "the dialog was created" and 121 * "the user clicked on a selection result", since only the latter should wipe out the 122 * manual user edit shown in the value text. 123 */ 124 private boolean mFirstSelect = true; 125 126 /** 127 * Label used to show the resolved value in the resource chooser. Only shown 128 * if the {@link #mResourceResolver} field is set. 129 */ 130 private Label mResolvedLabel; 131 132 /** Resource resolver used to show actual values for resources selected. (Optional). */ 133 private ResourceResolver mResourceResolver; 134 135 /** 136 * Creates a Resource Chooser dialog. 137 * @param project Project being worked on 138 * @param type The type of the resource to choose 139 * @param projectResources The repository for the project 140 * @param frameworkResources The Framework resource repository 141 * @param parent the parent shell 142 */ ResourceChooser(IProject project, ResourceType type, ResourceRepository projectResources, ResourceRepository frameworkResources, Shell parent)143 public ResourceChooser(IProject project, ResourceType type, 144 ResourceRepository projectResources, 145 ResourceRepository frameworkResources, 146 Shell parent) { 147 super(parent, new ResourceLabelProvider()); 148 mProject = project; 149 150 mResourceType = type; 151 mProjectResources = projectResources; 152 mFrameworkResources = frameworkResources; 153 154 mProjectResourcePattern = Pattern.compile( 155 PREFIX_RESOURCE_REF + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ 156 157 mSystemResourcePattern = Pattern.compile( 158 PREFIX_ANDROID_RESOURCE_REF + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ 159 160 setTitle("Resource Chooser"); 161 setMessage(String.format("Choose a %1$s resource", 162 mResourceType.getDisplayName().toLowerCase(Locale.US))); 163 } 164 165 /** 166 * Sets whether this dialog should show the value field as a separate text 167 * value (and take the resulting value of the dialog from this text field 168 * rather than from the selection) 169 * 170 * @param showValueText if true, show the value text field 171 */ setShowValueText(boolean showValueText)172 public void setShowValueText(boolean showValueText) { 173 mShowValueText = showValueText; 174 } 175 176 /** 177 * Sets the resource resolver to use to show resolved values for the current 178 * selection 179 * 180 * @param resourceResolver the resource resolver to use 181 */ setResourceResolver(ResourceResolver resourceResolver)182 public void setResourceResolver(ResourceResolver resourceResolver) { 183 mResourceResolver = resourceResolver; 184 } 185 186 /** 187 * Sets the {@link ResourcePreviewHelper} to use to preview drawable 188 * resources, if any 189 * 190 * @param previewHelper the helper to use 191 */ setPreviewHelper(ResourcePreviewHelper previewHelper)192 public void setPreviewHelper(ResourcePreviewHelper previewHelper) { 193 mPreviewHelper = previewHelper; 194 } 195 196 @Override create()197 public void create() { 198 super.create(); 199 200 if (mShowValueText) { 201 mEditValueText.selectAll(); 202 mEditValueText.setFocus(); 203 } 204 } 205 206 @Override createButtonsForButtonBar(Composite parent)207 protected void createButtonsForButtonBar(Composite parent) { 208 createButton(parent, CLEAR_BUTTON_ID, "Clear", false /*defaultButton*/); 209 super.createButtonsForButtonBar(parent); 210 } 211 212 @Override buttonPressed(int buttonId)213 protected void buttonPressed(int buttonId) { 214 super.buttonPressed(buttonId); 215 216 if (buttonId == CLEAR_BUTTON_ID) { 217 assert CLEAR_RETURN_CODE != Window.OK && CLEAR_RETURN_CODE != Window.CANCEL; 218 setReturnCode(CLEAR_RETURN_CODE); 219 close(); 220 } 221 } 222 setCurrentResource(String resource)223 public void setCurrentResource(String resource) { 224 mCurrentResource = resource; 225 226 if (mShowValueText && mEditValueText != null) { 227 mEditValueText.setText(resource); 228 } 229 } 230 getCurrentResource()231 public String getCurrentResource() { 232 return mCurrentResource; 233 } 234 setInputValidator(IInputValidator inputValidator)235 public void setInputValidator(IInputValidator inputValidator) { 236 mInputValidator = inputValidator; 237 } 238 239 @Override computeResult()240 protected void computeResult() { 241 if (mShowValueText) { 242 mCurrentResource = mEditValueText.getText(); 243 if (mCurrentResource.length() == 0) { 244 mCurrentResource = null; 245 } 246 return; 247 } 248 249 computeResultFromSelection(); 250 } 251 computeResultFromSelection()252 private void computeResultFromSelection() { 253 if (getSelectionIndex() == -1) { 254 mCurrentResource = null; 255 return; 256 } 257 258 Object[] elements = getSelectedElements(); 259 if (elements.length == 1 && elements[0] instanceof ResourceItem) { 260 ResourceItem item = (ResourceItem)elements[0]; 261 262 mCurrentResource = item.getXmlString(mResourceType, mSystemButton.getSelection()); 263 264 if (mInputValidator != null && mInputValidator.isValid(mCurrentResource) != null) { 265 mCurrentResource = null; 266 } 267 } 268 } 269 270 @Override createDialogArea(Composite parent)271 protected Control createDialogArea(Composite parent) { 272 Composite top = (Composite)super.createDialogArea(parent); 273 274 createMessageArea(top); 275 276 createButtons(top); 277 createFilterText(top); 278 createFilteredList(top); 279 280 // create the "New Resource" button 281 createNewResButtons(top); 282 283 // Optionally create the value text field, if {@link #mShowValueText} is true 284 createValueField(top); 285 286 setupResourceList(); 287 selectResourceString(mCurrentResource); 288 289 return top; 290 } 291 292 /** 293 * Creates the radio button to switch between project and system resources. 294 * @param top the parent composite 295 */ createButtons(Composite top)296 private void createButtons(Composite top) { 297 mProjectButton = new Button(top, SWT.RADIO); 298 mProjectButton.setText("Project Resources"); 299 mProjectButton.addSelectionListener(new SelectionAdapter() { 300 @Override 301 public void widgetSelected(SelectionEvent e) { 302 super.widgetSelected(e); 303 if (mProjectButton.getSelection()) { 304 // Clear selection before changing the list contents. This works around 305 // a bug in the superclass where switching to the framework resources, 306 // choosing one of the last resources, then switching to the project 307 // resources would cause an exception when calling getSelection() because 308 // selection state doesn't get cleared when we set new contents on 309 // the filtered list. 310 fFilteredList.setSelection(new int[0]); 311 setupResourceList(); 312 updateNewButton(false /*isSystem*/); 313 updateValue(); 314 } 315 } 316 }); 317 mSystemButton = new Button(top, SWT.RADIO); 318 mSystemButton.setText("System Resources"); 319 mSystemButton.addSelectionListener(new SelectionAdapter() { 320 @Override 321 public void widgetSelected(SelectionEvent e) { 322 super.widgetSelected(e); 323 if (mSystemButton.getSelection()) { 324 fFilteredList.setSelection(new int[0]); 325 setupResourceList(); 326 updateNewButton(true /*isSystem*/); 327 updateValue(); 328 } 329 } 330 }); 331 } 332 333 /** 334 * Creates the "New Resource" button. 335 * @param top the parent composite 336 */ createNewResButtons(Composite top)337 private void createNewResButtons(Composite top) { 338 mNewButton = new Button(top, SWT.NONE); 339 340 String title = String.format("New %1$s...", mResourceType.getDisplayName()); 341 if (mResourceType == ResourceType.DRAWABLE) { 342 title = "Create New Icon..."; 343 } 344 mNewButton.setText(title); 345 346 mNewButton.addSelectionListener(new SelectionAdapter() { 347 @Override 348 public void widgetSelected(SelectionEvent e) { 349 super.widgetSelected(e); 350 351 if (mResourceType == ResourceType.STRING) { 352 // Special case: Use Extract String refactoring wizard UI 353 String newName = createNewString(); 354 selectAddedItem(newName); 355 } else if (mResourceType == ResourceType.DRAWABLE) { 356 // Special case: Use the "Create Icon Set" wizard 357 OpenCreateAssetSetWizardAction action = 358 new OpenCreateAssetSetWizardAction(mProject); 359 action.run(); 360 List<IResource> files = action.getCreatedFiles(); 361 if (files != null && files.size() > 0) { 362 String newName = AdtUtils.stripAllExtensions(files.get(0).getName()); 363 // Recompute the "current resource" to select the new id 364 ResourceItem[] items = setupResourceList(); 365 selectItemName(newName, items); 366 } 367 } else { 368 if (ResourceHelper.isValueBasedResourceType(mResourceType)) { 369 String newName = createNewValue(mResourceType); 370 selectAddedItem(newName); 371 } else { 372 String newName = createNewFile(mResourceType); 373 selectAddedItem(newName); 374 } 375 } 376 } 377 378 private void selectAddedItem(String newName) { 379 // Recompute the "current resource" to select the new id 380 ResourceItem[] items = setupResourceList(); 381 382 // Ensure that the name is in the list. There's a delay after 383 // an item is added (until the builder runs and processes the delta) 384 // so if it's not in the list, add it 385 boolean found = false; 386 for (ResourceItem item : items) { 387 if (newName.equals(item.getName())) { 388 found = true; 389 break; 390 } 391 } 392 if (!found) { 393 ResourceItem[] newItems = new ResourceItem[items.length + 1]; 394 System.arraycopy(items, 0, newItems, 0, items.length); 395 newItems[items.length] = new ResourceItem(newName); 396 items = newItems; 397 Arrays.sort(items); 398 setListElements(items); 399 fFilteredList.setEnabled(newItems.length > 0); 400 } 401 402 selectItemName(newName, items); 403 } 404 }); 405 } 406 407 /** 408 * Creates the value text field. 409 * 410 * @param top the parent composite 411 */ createValueField(Composite top)412 private void createValueField(Composite top) { 413 if (mShowValueText) { 414 mEditValueText = new Text(top, SWT.BORDER); 415 if (mCurrentResource != null) { 416 mEditValueText.setText(mCurrentResource); 417 } 418 mEditValueText.addModifyListener(this); 419 420 GridData data = new GridData(); 421 data.grabExcessVerticalSpace = false; 422 data.grabExcessHorizontalSpace = true; 423 data.horizontalAlignment = GridData.FILL; 424 data.verticalAlignment = GridData.BEGINNING; 425 mEditValueText.setLayoutData(data); 426 mEditValueText.setFont(top.getFont()); 427 } 428 429 if (mResourceResolver != null) { 430 mResolvedLabel = new Label(top, SWT.NONE); 431 GridData data = new GridData(); 432 data.grabExcessVerticalSpace = false; 433 data.grabExcessHorizontalSpace = true; 434 data.horizontalAlignment = GridData.FILL; 435 data.verticalAlignment = GridData.BEGINNING; 436 mResolvedLabel.setLayoutData(data); 437 } 438 } 439 updateResolvedLabel()440 private void updateResolvedLabel() { 441 if (mResourceResolver == null) { 442 return; 443 } 444 445 String v = null; 446 if (mCurrentResource != null) { 447 v = mCurrentResource; 448 if (mCurrentResource.startsWith(PREFIX_RESOURCE_REF)) { 449 ResourceValue value = mResourceResolver.findResValue(mCurrentResource, false); 450 if (value != null) { 451 v = value.getValue(); 452 } 453 } 454 } 455 456 if (v == null) { 457 v = ""; 458 } 459 460 mResolvedLabel.setText(String.format("Resolved Value: %1$s", v)); 461 } 462 463 @Override handleSelectionChanged()464 protected void handleSelectionChanged() { 465 super.handleSelectionChanged(); 466 if (mInputValidator != null) { 467 Object[] elements = getSelectedElements(); 468 if (elements.length == 1 && elements[0] instanceof ResourceItem) { 469 ResourceItem item = (ResourceItem)elements[0]; 470 String current = item.getXmlString(mResourceType, mSystemButton.getSelection()); 471 String error = mInputValidator.isValid(current); 472 IStatus status; 473 if (error != null) { 474 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error); 475 } else { 476 status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID, null); 477 } 478 updateStatus(status); 479 } 480 } 481 482 updateValue(); 483 } 484 updateValue()485 private void updateValue() { 486 if (mPreviewHelper != null) { 487 computeResult(); 488 mPreviewHelper.updatePreview(mResourceType, mCurrentResource); 489 } 490 491 if (mShowValueText) { 492 if (mFirstSelect) { 493 mFirstSelect = false; 494 mEditValueText.selectAll(); 495 } else { 496 computeResultFromSelection(); 497 mEditValueText.setText(mCurrentResource != null ? mCurrentResource : ""); 498 } 499 } 500 501 if (mResourceResolver != null) { 502 if (!mShowValueText) { 503 computeResultFromSelection(); 504 } 505 updateResolvedLabel(); 506 } 507 } 508 createNewFile(ResourceType type)509 private String createNewFile(ResourceType type) { 510 // Show a name/value dialog entering the key name and the value 511 Shell shell = AdtPlugin.getDisplay().getActiveShell(); 512 if (shell == null) { 513 return null; 514 } 515 516 ResourceNameValidator validator = ResourceNameValidator.create(true /*allowXmlExtension*/, 517 mProject, mResourceType); 518 InputDialog d = new InputDialog( 519 AdtPlugin.getDisplay().getActiveShell(), 520 "Enter name", // title 521 "Enter name", 522 "", //$NON-NLS-1$ 523 validator); 524 if (d.open() == Window.OK) { 525 String name = d.getValue().trim(); 526 if (name.length() == 0) { 527 return null; 528 } 529 530 Pair<IFile, IRegion> resource = ResourceHelper.createResource(mProject, type, name, 531 null); 532 if (resource != null) { 533 return name; 534 } 535 } 536 537 return null; 538 } 539 540 createNewValue(ResourceType type)541 private String createNewValue(ResourceType type) { 542 // Show a name/value dialog entering the key name and the value 543 Shell shell = AdtPlugin.getDisplay().getActiveShell(); 544 if (shell == null) { 545 return null; 546 } 547 NameValueDialog dialog = new NameValueDialog(shell, getFilter()); 548 if (dialog.open() != Window.OK) { 549 return null; 550 } 551 552 String name = dialog.getName(); 553 String value = dialog.getValue(); 554 if (name.length() == 0 || value.length() == 0) { 555 return null; 556 } 557 558 Pair<IFile, IRegion> resource = ResourceHelper.createResource(mProject, type, name, value); 559 if (resource != null) { 560 return name; 561 } 562 563 return null; 564 } 565 createNewString()566 private String createNewString() { 567 ExtractStringRefactoring ref = new ExtractStringRefactoring( 568 mProject, true /*enforceNew*/); 569 RefactoringWizard wizard = new ExtractStringWizard(ref, mProject); 570 RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard); 571 try { 572 IWorkbench w = PlatformUI.getWorkbench(); 573 if (op.run(w.getDisplay().getActiveShell(), wizard.getDefaultPageTitle()) == 574 IDialogConstants.OK_ID) { 575 return ref.getXmlStringId(); 576 } 577 } catch (InterruptedException ex) { 578 // Interrupted. Pass. 579 } 580 581 return null; 582 } 583 584 /** 585 * Setups the current list. 586 */ setupResourceList()587 private ResourceItem[] setupResourceList() { 588 Collection<ResourceItem> items = null; 589 if (mProjectButton.getSelection()) { 590 items = mProjectResources.getResourceItemsOfType(mResourceType); 591 } else if (mSystemButton.getSelection()) { 592 items = mFrameworkResources.getResourceItemsOfType(mResourceType); 593 } 594 595 if (items == null) { 596 items = Collections.emptyList(); 597 } 598 599 ResourceItem[] arrayItems = items.toArray(new ResourceItem[items.size()]); 600 601 // sort the array 602 Arrays.sort(arrayItems); 603 604 setListElements(arrayItems); 605 fFilteredList.setEnabled(arrayItems.length > 0); 606 607 return arrayItems; 608 } 609 610 /** 611 * Select an item by its name, if possible. 612 */ selectItemName(String itemName, ResourceItem[] items)613 private void selectItemName(String itemName, ResourceItem[] items) { 614 if (itemName == null || items == null) { 615 return; 616 } 617 618 for (ResourceItem item : items) { 619 if (itemName.equals(item.getName())) { 620 setSelection(new Object[] { item }); 621 break; 622 } 623 } 624 } 625 626 /** 627 * Select an item by its full resource string. 628 * This also selects between project and system repository based on the resource string. 629 */ selectResourceString(String resourceString)630 private void selectResourceString(String resourceString) { 631 boolean isSystem = false; 632 String itemName = null; 633 634 if (resourceString != null) { 635 // Is this a system resource? 636 // If not a system resource or if they are not available, this will be a project res. 637 Matcher m = mSystemResourcePattern.matcher(resourceString); 638 if (m.matches()) { 639 itemName = m.group(1); 640 isSystem = true; 641 } 642 643 if (!isSystem && itemName == null) { 644 // Try to match project resource name 645 m = mProjectResourcePattern.matcher(resourceString); 646 if (m.matches()) { 647 itemName = m.group(1); 648 } 649 } 650 } 651 652 // Update the repository selection 653 mProjectButton.setSelection(!isSystem); 654 mSystemButton.setSelection(isSystem); 655 updateNewButton(isSystem); 656 657 // Update the list 658 ResourceItem[] items = setupResourceList(); 659 660 // If we have a selection name, select it 661 if (itemName != null) { 662 selectItemName(itemName, items); 663 } 664 } 665 updateNewButton(boolean isSystem)666 private void updateNewButton(boolean isSystem) { 667 mNewButton.setEnabled(!isSystem && ResourceHelper.canCreateResourceType(mResourceType)); 668 } 669 670 // ---- Implements ModifyListener ---- 671 672 @Override modifyText(ModifyEvent e)673 public void modifyText(ModifyEvent e) { 674 if (e.getSource() == mEditValueText && mResourceResolver != null) { 675 mCurrentResource = mEditValueText.getText(); 676 677 if (mCurrentResource.startsWith(PREFIX_RESOURCE_REF)) { 678 if (mProjectResourcePattern.matcher(mCurrentResource).matches() || 679 mSystemResourcePattern.matcher(mCurrentResource).matches()) { 680 updateResolvedLabel(); 681 } 682 } else { 683 updateResolvedLabel(); 684 } 685 } 686 } 687 688 /** Dialog asking for a Name/Value pair */ 689 private class NameValueDialog extends SelectionStatusDialog implements Listener { 690 private org.eclipse.swt.widgets.Text mNameText; 691 private org.eclipse.swt.widgets.Text mValueText; 692 private String mInitialName; 693 private String mName; 694 private String mValue; 695 private ResourceNameValidator mValidator; 696 NameValueDialog(Shell parent, String initialName)697 public NameValueDialog(Shell parent, String initialName) { 698 super(parent); 699 mInitialName = initialName; 700 } 701 702 @Override createDialogArea(Composite parent)703 protected Control createDialogArea(Composite parent) { 704 Composite container = new Composite(parent, SWT.NONE); 705 container.setLayout(new GridLayout(2, false)); 706 GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); 707 // Wide enough to accommodate the error label 708 gridData.widthHint = 500; 709 container.setLayoutData(gridData); 710 711 712 Label nameLabel = new Label(container, SWT.NONE); 713 nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 714 nameLabel.setText("Name:"); 715 716 mNameText = new org.eclipse.swt.widgets.Text(container, SWT.BORDER); 717 mNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 718 if (mInitialName != null) { 719 mNameText.setText(mInitialName); 720 mNameText.selectAll(); 721 } 722 723 Label valueLabel = new Label(container, SWT.NONE); 724 valueLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 725 valueLabel.setText("Value:"); 726 727 mValueText = new org.eclipse.swt.widgets.Text(container, SWT.BORDER); 728 mValueText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 729 730 mNameText.addListener(SWT.Modify, this); 731 mValueText.addListener(SWT.Modify, this); 732 733 validate(); 734 735 return container; 736 } 737 738 @Override computeResult()739 protected void computeResult() { 740 mName = mNameText.getText().trim(); 741 mValue = mValueText.getText().trim(); 742 } 743 getName()744 private String getName() { 745 return mName; 746 } 747 getValue()748 private String getValue() { 749 return mValue; 750 } 751 752 @Override handleEvent(Event event)753 public void handleEvent(Event event) { 754 validate(); 755 } 756 validate()757 private void validate() { 758 IStatus status; 759 computeResult(); 760 if (mName.length() == 0) { 761 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter a name"); 762 } else if (mValue.length() == 0) { 763 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter a value"); 764 } else { 765 if (mValidator == null) { 766 mValidator = ResourceNameValidator.create(false, mProject, mResourceType); 767 } 768 String error = mValidator.isValid(mName); 769 if (error != null) { 770 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error); 771 } else { 772 status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID, null); 773 } 774 } 775 updateStatus(status); 776 } 777 } 778 779 /** 780 * Open the resource chooser for the given type, associated with the given 781 * editor 782 * 783 * @param graphicalEditor the editor associated with the resource to be 784 * chosen (used to find the associated Android target to be used 785 * for framework resources etc) 786 * @param type the resource type to be chosen 787 * @param currentValue the current value, or null 788 * @param validator a validator to be used, or null 789 * @return the chosen resource, null if cancelled and "" if value should be 790 * cleared 791 */ chooseResource( @onNull GraphicalEditorPart graphicalEditor, @NonNull ResourceType type, String currentValue, IInputValidator validator)792 public static String chooseResource( 793 @NonNull GraphicalEditorPart graphicalEditor, 794 @NonNull ResourceType type, 795 String currentValue, IInputValidator validator) { 796 AndroidXmlEditor editor = graphicalEditor.getEditorDelegate().getEditor(); 797 IProject project = editor.getProject(); 798 if (project != null) { 799 // get the resource repository for this project and the system resources. 800 ResourceRepository projectRepository = ResourceManager.getInstance() 801 .getProjectResources(project); 802 Shell shell = AdtPlugin.getDisplay().getActiveShell(); 803 if (shell == null) { 804 return null; 805 } 806 807 AndroidTargetData data = editor.getTargetData(); 808 ResourceRepository systemRepository = data.getFrameworkResources(); 809 810 // open a resource chooser dialog for specified resource type. 811 ResourceChooser dlg = new ResourceChooser(project, type, projectRepository, 812 systemRepository, shell); 813 dlg.setPreviewHelper(new ResourcePreviewHelper(dlg, graphicalEditor)); 814 815 // When editing Strings, allow editing the value text directly. When we 816 // get inline editing support (where values entered directly into the 817 // textual widget are translated automatically into a resource) this can 818 // go away. 819 if (type == ResourceType.STRING) { 820 dlg.setResourceResolver(graphicalEditor.getResourceResolver()); 821 dlg.setShowValueText(true); 822 } else if (type == ResourceType.DIMEN || type == ResourceType.INTEGER) { 823 dlg.setResourceResolver(graphicalEditor.getResourceResolver()); 824 } 825 826 if (validator != null) { 827 // Ensure wide enough to accommodate validator error message 828 dlg.setSize(85, 10); 829 dlg.setInputValidator(validator); 830 } 831 832 dlg.setCurrentResource(currentValue); 833 834 int result = dlg.open(); 835 if (result == ResourceChooser.CLEAR_RETURN_CODE) { 836 return ""; //$NON-NLS-1$ 837 } else if (result == Window.OK) { 838 return dlg.getCurrentResource(); 839 } 840 } 841 842 return null; 843 } 844 } 845