protected void rebuildUi()

in flutter-idea/src/io/flutter/editor/PropertyEditorPanel.java [455:603]


  protected void rebuildUi() {
    // TODO(jacobr): be lazier about only rebuilding what changed.
    final Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
    if (focusOwner != null) {
      if (isAncestorOf(focusOwner)) {
        for (Map.Entry<String, JComponent> entry : fields.entrySet()) {
          if (entry.getValue().isAncestorOf(focusOwner) || entry.getValue() == focusOwner) {
            previouslyFocusedProperty = entry.getKey();
            break;
          }
        }
      }
      else {
        previouslyFocusedProperty = null;
      }
    }
    removeAll();
    // Layout Constraints
    // Column constraints
    final MigLayout manager = new MigLayout(
      "insets 3", // Layout Constraints
      fixedWidth ? "[::120]5[:20:400]" : "[::120]5[grow]", // Column constraints
      "[23]4[23]"
    );
    setLayout(manager);
    int added = 0;
    for (FlutterWidgetProperty property : properties) {
      final String name = property.getName();
      if (name.equals("child") || name.equals("children")) {
        continue;
      }
      if (name.equals("Container")) {
        final List<FlutterWidgetProperty> containerProperties = property.getChildren();
        // TODO(jacobr): add support for container properties.
        continue;
      }
      final String documentation = property.getDocumentation();
      JComponent field = null;

      if (property.getEditor() == null) {
        // TODO(jacobr): detect color properties more robustly.
        final boolean colorProperty = name.equals("color");
        final String colorPropertyName = name;
        if (colorProperty) {
          field = buildColorProperty(name, property);
        }
        else {
          String expression = property.getExpression();
          if (expression == null) {
            expression = "";
          }
          final JBTextField textField = new JBTextField(expression);
          // Make sure we show the text at the beginning of the text field.
          // The default is to show the end if the content scrolls which looks
          // bad in a property editor.
          textField.setCaretPosition(0);
          addTextFieldListeners(name, textField);
          field = textField;
        }
      }
      else {
        final FlutterWidgetPropertyEditor editor = property.getEditor();
        if (editor.getEnumItems() != null) {
          final ComboBox<EnumValueWrapper> comboBox = new ComboBox<>();
          comboBox.setEditable(true);
          comboBox.setModel(new PropertyEnumComboBoxModel(property));

          // TODO(jacobr): need a bit more padding around comboBox to make it match the JBTextField.
          field = comboBox;
          comboBox.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
              final EnumValueWrapper wrapper = (EnumValueWrapper)e.getItem();
              if (wrapper.item != null) {
                setParsedPropertyValue(name, new FlutterWidgetPropertyValue(null, null, null, null, wrapper.item, null), false);
              }
              else {
                setPropertyValue(name, wrapper.expression);
              }
            }
          });
        }
        else {
          // TODO(jacobr): use IntegerField and friends when appropriate.
          // TODO(jacobr): we should probably use if (property.isSafeToUpdate())
          // but that currently it seems to have a bunch of false positives.
          final String kind = property.getEditor().getKind();
          if (Objects.equals(kind, FlutterWidgetPropertyEditorKind.BOOL)) {
            // TODO(jacobr): show as boolean.
          }
          final JBTextField textField = new JBTextField(property.getExpression());
          // Make sure we show the text at the beginning of the text field.
          // The default is to show the end if the content scrolls which looks
          // bad in a property editor.
          textField.setCaretPosition(0);
          field = textField;
          addTextFieldListeners(name, textField);
        }
      }

      if (name.equals("data")) {
        if (documentation != null) {
          field.setToolTipText(documentation);
        }
        else {
          field.setToolTipText("data");
        }
        add(field, "span, growx");
      }
      else {
        final String propertyName = property.getName();
        final JBLabel label = new JBLabel(propertyName);
        // 120 is the max width of the column but that does not appear to be
        // applied unless it is also set here.
        add(label, "right, wmax 120px");
        final ArrayList<String> tooltipBlocks = new ArrayList<>();
        tooltipBlocks.add("<strong>" + propertyName + "</strong>");

        if (documentation != null) {
          tooltipBlocks.add(documentation);
        }
        // Use multiple line breaks so there is a clear separation between blocks.
        label.setToolTipText(Joiner.on("\n\n").join(tooltipBlocks));

        add(field, "wrap, growx");
      }
      if (documentation != null) {
        field.setToolTipText(documentation);
      }
      // Hack: set the preferred width of the ui elements to a small value
      // so it doesn't cause the overall layout to be wider than it should
      // be.
      if (!fixedWidth) {
        setPreferredFieldSize(field);
      }

      fields.put(name, field);
      added++;
    }
    if (previouslyFocusedProperty != null && fields.containsKey(previouslyFocusedProperty)) {
      fields.get(previouslyFocusedProperty).requestFocus();
    }

    if (added == 0) {
      add(new JBLabel("No editable properties"));
    }
    // TODO(jacobr): why is this needed?
    revalidate();
    repaint();
  }