Skip to content

Commit

Permalink
feat(ui): Allow filtering components in source structure
Browse files Browse the repository at this point in the history
Introduces a dropdown which allows to select if the source structure box should display all components, only the visible ones or the non visible ones.

Change-Id: I1121c78c82a9eddab1abc696d5af865460fcad50
  • Loading branch information
barreeeiroo authored and ewpatton committed Sep 12, 2023
1 parent a699e8c commit 2b1a9ce
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,18 @@ public interface OdeMessages extends Messages, AutogeneratedOdeMessages {
@Description("Caption for source structure box.")
String sourceStructureBoxCaption();

@DefaultMessage("All Components")
@Description("Caption for source structure box.")
String sourceStructureBoxCaptionAll();

@DefaultMessage("Visible Components")
@Description("Caption for source structure box.")
String sourceStructureBoxCaptionVisible();

@DefaultMessage("Non-visible Components")
@Description("Caption for source structure box.")
String sourceStructureBoxCaptionNonVisible();

// Used in BlocksToolkit (SubsetJSONPropertyEditor)

@DefaultMessage("Blocks Toolkit")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.boxes;

import com.google.appinventor.client.editor.simple.components.MockForm;
import com.google.appinventor.client.editor.youngandroid.YaFormEditor;
import com.google.appinventor.client.explorer.SourceStructureExplorer;

public interface ISourceStructureBox {
/**
* Method to retrieve the rendered source structure explorer from the "child" boxes.
* @return SourceStructureExplorer
*/
SourceStructureExplorer getSourceStructureExplorer();

/**
* Method render the "child" boxes.
*/
void show(MockForm form);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2011-2023 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

Expand All @@ -9,20 +9,19 @@
import static com.google.appinventor.client.Ode.MESSAGES;

import com.google.appinventor.client.editor.simple.components.MockForm;
import com.google.appinventor.client.editor.youngandroid.YaFormEditor;
import com.google.appinventor.client.explorer.SourceStructureExplorer;
import com.google.appinventor.client.widgets.boxes.Box;
import com.google.appinventor.common.version.AppInventorFeatures;
import com.google.gwt.user.client.ui.DockPanel;

/**
* Box implementation for source structure explorer.
*
*/
public final class SourceStructureBox extends Box {
public class SourceStructureBox extends Box implements ISourceStructureBox {
// Singleton source structure explorer box instance
private static final SourceStructureBox INSTANCE = new SourceStructureBox();

// Source structure explorer
private final SourceStructureExplorer sourceStructureExplorer;
// Singleton source structure explorer child instance
private static ISourceStructureBox SUBINSTANCE;

/**
* Return the singleton source structure explorer box.
Expand All @@ -42,26 +41,39 @@ private SourceStructureBox() {
false, // minimizable
false); // removable

sourceStructureExplorer = new SourceStructureExplorer();
// Creates the child instance according to the enabled features.
SUBINSTANCE = AppInventorFeatures.enableFutureFeatures()
? new SourceStructureBoxNew(this)
: new SourceStructureBoxClassic();

setContent(sourceStructureExplorer);
setContent(SUBINSTANCE.getSourceStructureExplorer());
}

/**
* Returns source structure explorer associated with box.
*
* @return source structure explorer
* @return source structure explorer
*/
public SourceStructureExplorer getSourceStructureExplorer() {
return sourceStructureExplorer;
return SUBINSTANCE.getSourceStructureExplorer();
}

/**
* Calls the child box and renders it according to its behaviour.
* @param form current form
*/
public void show(MockForm form) {
sourceStructureExplorer.updateTree(form.buildComponentsTree(),
getSourceStructureExplorer().updateTree(form.buildComponentsTree(),
form.getLastSelectedComponent().getSourceStructureExplorerItem());
sourceStructureExplorer.setVisible(true);
this.setVisible(true);
setContent(sourceStructureExplorer);
getSourceStructureBox().setVisible(true);
setContent(SUBINSTANCE.getSourceStructureExplorer());
}

/**
* Returns the header container for the source structure box (used by childs).
* @return DockPanel header container
*/
public DockPanel getHeaderContainer() {
return super.getHeaderContainer();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2023 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.boxes;

import com.google.appinventor.client.editor.simple.components.MockForm;
import com.google.appinventor.client.explorer.SourceStructureExplorer;

/**
* Box implementation for source structure explorer (classic style).
*/
public final class SourceStructureBoxClassic implements ISourceStructureBox {
private final SourceStructureExplorer sourceStructureExplorer = new SourceStructureExplorer();

public SourceStructureBoxClassic() {
super();
}

public void show(MockForm form) {
sourceStructureExplorer.updateTree(form.buildComponentsTree(),
form.getLastSelectedComponent().getSourceStructureExplorerItem());
sourceStructureExplorer.setVisible(true);
}

public SourceStructureExplorer getSourceStructureExplorer() {
return sourceStructureExplorer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2023 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.boxes;

import com.google.appinventor.client.Ode;
import com.google.appinventor.client.editor.simple.components.MockForm;
import com.google.appinventor.client.editor.youngandroid.YaFormEditor;
import com.google.appinventor.client.explorer.SourceStructureExplorer;
import com.google.appinventor.client.widgets.DropDownButton;
import com.google.appinventor.client.widgets.DropDownItem;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.DockPanel;

import java.util.ArrayList;
import java.util.List;

import static com.google.appinventor.client.Ode.MESSAGES;

/**
* Box implementation for source structure explorer (new style, with filters).
*/
public final class SourceStructureBoxNew implements ISourceStructureBox {
private Integer view = 1;

private final DropDownButton dropDownButton;
private final SourceStructureExplorer sourceStructureExplorer = new SourceStructureExplorer(false);

/**
* Creates new source structure explorer box.
*/
public SourceStructureBoxNew(SourceStructureBox container) {
super();

List<DropDownItem> items = new ArrayList<>();
items.add(new DropDownItem("AllComponents", MESSAGES.sourceStructureBoxCaptionAll(), new SelectSourceView(1)));
items.add(new DropDownItem("VisibleComponents", MESSAGES.sourceStructureBoxCaptionVisible(), new SelectSourceView(2)));
items.add(new DropDownItem("NonVisibleComponents", MESSAGES.sourceStructureBoxCaptionNonVisible(), new SelectSourceView(3)));

dropDownButton = new DropDownButton("ComponentsTreeFilter", "", items, false);
dropDownButton.addStyleName("components-tree-filter");
dropDownButton.setCaption(MESSAGES.sourceStructureBoxCaptionAll());

container.getHeaderContainer().clear();
container.getHeaderContainer().add(dropDownButton, DockPanel.LINE_START);
}

public void show(MockForm form) {
sourceStructureExplorer.updateTree(form.buildComponentsTree(view),
form.getLastSelectedComponent().getSourceStructureExplorerItem());
updateSourceDropdownButtonCaption();

sourceStructureExplorer.setVisible(true);
}

public SourceStructureExplorer getSourceStructureExplorer() {
return sourceStructureExplorer;
}

public void setView(Integer view) {
this.view = view;
}

public Integer getView() {
return view;
}

private void updateSourceDropdownButtonCaption() {
String c;
switch (view) {
case 1:
c = MESSAGES.sourceStructureBoxCaptionAll();
break;
case 2:
c = MESSAGES.sourceStructureBoxCaptionVisible();
break;
case 3:
c = MESSAGES.sourceStructureBoxCaptionNonVisible();
break;
default:
c = MESSAGES.sourceStructureBoxCaption();
break;
}

dropDownButton.setCaption(c);
}

private final class SelectSourceView implements Command {
/* 1 - > All components
* 2 - > Visible components
* 3 - > Non-visible components
*/
private final Integer view;

SelectSourceView(Integer view) {
super();
this.view = view;
}

@Override
public void execute() {
MockForm form = ((YaFormEditor) Ode.getInstance().getCurrentFileEditor()).getForm();
sourceStructureExplorer.updateTree(form.buildComponentsTree(view),
form.getForm().getLastSelectedComponent().getSourceStructureExplorerItem());
SourceStructureBoxNew.this.setView(view);

updateSourceDropdownButtonCaption();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,23 @@ public final MockLayout getLayout() {
return layout;
}

@Override
protected TreeItem buildTree() {
protected TreeItem buildTree(Integer view) {
TreeItem itemNode = super.buildTree();
//hide all containers except form if only nonvisible components are to be shown
//in such a case, we need only the form's treeItem because all non-visible components are attached to it
if (view == 3 && !isForm()) {
itemNode.setVisible(false);
}

// Recursively build the tree for child components
for (MockComponent child : children) {
itemNode.addItem(child.buildTree());
TreeItem childNode = child.buildTree();
if (view == 2 && child instanceof MockNonVisibleComponent) {
childNode.setVisible(false);
} else if (view == 3 && child instanceof MockVisibleComponent) {
childNode.setVisible(false);
}
itemNode.addItem(childNode);
}

itemNode.setState(expanded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,17 @@ public final void setPasteTarget(MockContainer target) {
* @return tree showing the component hierarchy of the form
*/
public TreeItem buildComponentsTree() {
return buildTree();
return buildComponentsTree(1);
}

/**
* Builds a tree of the component hierarchy of the form for display in the
* {@code SourceStructureExplorer}.
*
* @return tree showing the component hierarchy of the form
*/
public TreeItem buildComponentsTree(Integer view) {
return buildTree(view);
}

// PropertyChangeListener implementation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,14 @@ public void onBrowserEvent(Event event) {
}
}

public SourceStructureExplorer() {
this(true);
}

/**
* Creates a new source structure explorer.
*/
public SourceStructureExplorer() {
public SourceStructureExplorer(boolean includeButtonPanel) {
// Initialize UI elements
tree = new EventCaptureTree(Ode.getImageBundle());
tree.setAnimationEnabled(true);
Expand Down Expand Up @@ -174,8 +178,12 @@ public void onClick(ClickEvent event) {

VerticalPanel panel = new VerticalPanel();
panel.add(scrollPanel);
panel.add(new Label());
panel.add(buttonPanel);
// TODO([email protected]): With App Inventor's current layout, as of now this is the only place to
// render these buttons...
// if (includeButtonPanel) {
panel.add(new Label());
panel.add(buttonPanel);
// }
panel.setCellHorizontalAlignment(buttonPanel, HorizontalPanel.ALIGN_CENTER);
initWidget(panel);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,14 @@ Widget getHeader() {
return header;
}

/**
* Returns the box header container.
* @return header container
*/
public DockPanel getHeaderContainer() {
return headerContainer;
}

/**
* Invoked upon resizing of the box by the layout. Box height will remain
* unmodified.
Expand Down
6 changes: 6 additions & 0 deletions appinventor/appengine/war/static/css/Ya.css
Original file line number Diff line number Diff line change
Expand Up @@ -3072,3 +3072,9 @@ div.dropdiv p {
.listItem:nth-child(2n + 0) {
background: rgba(200, 200, 200, 0.1);
}

.components-tree-filter {
margin-top: 1px;
margin-left: 1px;
font-size: 11px;
}

0 comments on commit 2b1a9ce

Please sign in to comment.