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();
}