// -*- 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.explorer; import com.google.appinventor.client.Ode; import com.google.appinventor.client.output.OdeLog; import com.google.appinventor.client.widgets.TextButton; import com.google.gwt.event.dom.client.*; import com.google.gwt.event.logical.shared.*; import com.google.gwt.user.client.ui.*; import java.util.Iterator; import static com.google.appinventor.client.Ode.MESSAGES; /** * This explorer is used to outline the structure of a source file. Note that * this explorer is shared by all it's clients. That means that clients (most * likely editors) need to update its content upon activation. * * @author lizlooney@google.com (Liz Looney) */ public class SourceStructureExplorer extends Composite { // UI elements private final Tree tree; private final TextButton renameButton; private final TextButton deleteButton; /** * Creates a new source structure explorer. */ public SourceStructureExplorer() { // Initialize UI elements tree = new Tree(Ode.getImageBundle()); tree.setAnimationEnabled(true); tree.addCloseHandler(new CloseHandler<TreeItem>() { @Override public void onClose(CloseEvent<TreeItem> event) { TreeItem treeItem = event.getTarget(); if (treeItem != null) { Object userObject = treeItem.getUserObject(); if (userObject instanceof SourceStructureExplorerItem) { SourceStructureExplorerItem item = (SourceStructureExplorerItem) userObject; item.onStateChange(false); } } } }); tree.addOpenHandler(new OpenHandler<TreeItem>() { @Override public void onOpen(OpenEvent<TreeItem> event) { TreeItem treeItem = event.getTarget(); if (treeItem != null) { Object userObject = treeItem.getUserObject(); if (userObject instanceof SourceStructureExplorerItem) { SourceStructureExplorerItem item = (SourceStructureExplorerItem) userObject; item.onStateChange(true); } } } }); tree.addSelectionHandler(new SelectionHandler<TreeItem>() { @Override public void onSelection(SelectionEvent<TreeItem> event) { TreeItem treeItem = event.getSelectedItem(); if (treeItem != null) { Object userObject = treeItem.getUserObject(); if (userObject instanceof SourceStructureExplorerItem) { SourceStructureExplorerItem item = (SourceStructureExplorerItem) userObject; enableButtons(item); //showBlocks(item); item.onSelected(); } else { disableButtons(); //hideComponent(); } } else { disableButtons(); } } }); tree.addKeyDownHandler(new KeyDownHandler() { @Override public void onKeyDown(KeyDownEvent event) { int keyCode = event.getNativeKeyCode(); if (keyCode == KeyCodes.KEY_DELETE || keyCode == KeyCodes.KEY_BACKSPACE) { event.preventDefault(); deleteItemFromTree(); } } }); // Put a ScrollPanel around the tree. ScrollPanel scrollPanel = new ScrollPanel(tree); scrollPanel.setWidth("200px"); // wide enough to avoid a horizontal scrollbar most of the time scrollPanel.setHeight("480px"); // approximately the same height as the viewer HorizontalPanel buttonPanel = new HorizontalPanel(); buttonPanel.setStyleName("ode-PanelButtons"); buttonPanel.setSpacing(4); renameButton = new TextButton(MESSAGES.renameButton()); renameButton.setEnabled(false); renameButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { TreeItem treeItem = tree.getSelectedItem(); if (treeItem != null) { Object userObject = treeItem.getUserObject(); if (userObject instanceof SourceStructureExplorerItem) { SourceStructureExplorerItem item = (SourceStructureExplorerItem) userObject; item.rename(); } } } }); buttonPanel.add(renameButton); buttonPanel.setCellHorizontalAlignment(renameButton, HorizontalPanel.ALIGN_RIGHT); deleteButton = new TextButton(MESSAGES.deleteButton()); deleteButton.setEnabled(false); deleteButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { deleteItemFromTree(); } }); buttonPanel.add(deleteButton); buttonPanel.setCellHorizontalAlignment(deleteButton, HorizontalPanel.ALIGN_LEFT); VerticalPanel panel = new VerticalPanel(); panel.add(scrollPanel); panel.add(new Label()); panel.add(buttonPanel); panel.setCellHorizontalAlignment(buttonPanel, HorizontalPanel.ALIGN_CENTER); initWidget(panel); } private void deleteItemFromTree() { TreeItem treeItem = tree.getSelectedItem(); if (treeItem != null) { Object userObject = treeItem.getUserObject(); if (userObject instanceof SourceStructureExplorerItem) { SourceStructureExplorerItem item = (SourceStructureExplorerItem) userObject; item.delete(); } } } private void enableButtons(SourceStructureExplorerItem item) { renameButton.setEnabled(item.canRename()); deleteButton.setEnabled(item.canDelete()); } private void disableButtons() { renameButton.setEnabled(false); deleteButton.setEnabled(false); } /* move this logic to declarations of SourceStructureExplorerItem subtypes private void showBlocks(SourceStructureExplorerItem item) { // are we showing the blocks editor? if (Ode.getInstance().getCurrentFileEditor() instanceof YaBlocksEditor) { YaBlocksEditor editor = (YaBlocksEditor) Ode.getInstance().getCurrentFileEditor(); OdeLog.log("Showing item " + item.getItemName()); if (item.isComponent()) { editor.showComponentBlocks(item.getItemName()); } else { editor.showBuiltinBlocks(item.getItemName()); } } } private void hideComponent() { if (Ode.getInstance().getCurrentFileEditor() instanceof YaBlocksEditor) { YaBlocksEditor editor = (YaBlocksEditor) Ode.getInstance().getCurrentFileEditor(); OdeLog.log("Hiding selected item"); editor.hideComponentBlocks(); } } */ /** * Clears the tree. */ public void clearTree() { tree.clear(); disableButtons(); } /** * Updates the tree * * @param root the new root TreeItem * @param itemToSelect item to select, or null for no selected item */ public void updateTree(TreeItem root, SourceStructureExplorerItem itemToSelect) { TreeItem items[] = new TreeItem[1]; items[0] = root; updateTree(items, itemToSelect); } /** * Updates the tree * * @param roots An array of root items (all top level) * @param itemToSelect item to select, or null for no selected item */ public void updateTree(TreeItem[] roots, SourceStructureExplorerItem itemToSelect) { tree.clear(); for (TreeItem root : roots) { tree.addItem(root); } if (itemToSelect != null) { selectItem(itemToSelect, true); } else { disableButtons(); } } /** * Select or unselect an item in the tree * * @param item to select or unselect * @param select true to select, false to unselect */ private void selectItem(SourceStructureExplorerItem item, boolean select) { Iterator<TreeItem> iter = tree.treeItemIterator(); while (iter.hasNext()) { TreeItem treeItem = iter.next(); if (item.equals(treeItem.getUserObject())) { // NOTE(lizlooney) - It turns out that calling TreeItem.setSelected(true) doesn't actually // select the item in the tree. It looks selected, but Tree.getSelectedItem() will return // null. Instead, we have to call Tree.setSelectedItem. if (select) { tree.setSelectedItem(treeItem, false); // false means don't trigger a SelectionEvent enableButtons(item); //showBlocks(item); } else { tree.setSelectedItem(null, false); // false means don't trigger a SelectionEvent disableButtons(); //hideComponent(); } break; } } } /** * Select an item in the tree * * @param item item to select */ public void selectItem(SourceStructureExplorerItem item) { selectItem(item, true); } /** * Select an item in the tree * * @param item item to unselect */ public void unselectItem(SourceStructureExplorerItem item) { selectItem(item, false); } }