/* * ObjectBrowser.java * * Copyright (C) 2009-17 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.workbench.views.connections.ui; import java.util.HashSet; import java.util.Set; import org.rstudio.studio.client.workbench.views.connections.model.Connection; import org.rstudio.studio.client.workbench.views.connections.model.DatabaseObject; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.BorderStyle; import com.google.gwt.i18n.client.LocalizableResource.DefaultLocale; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.resources.client.ImageResource.ImageOptions; import com.google.gwt.user.cellview.client.CellTree; import com.google.gwt.user.cellview.client.CellTree.CellTreeMessages; import com.google.gwt.user.cellview.client.TreeNode; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.VerticalPanel; public class ObjectBrowser extends Composite implements RequiresResize { public ObjectBrowser() { // create scroll panel and set the vertical wrapper as it's widget scrollPanel_ = new ScrollPanel(); scrollPanel_.setSize("100%", "100%"); connection_ = null; // init widget initWidget(scrollPanel_); } public void clear() { if (objectsModel_ != null) objectsModel_.clear(); connection_ = null; objectsModel_ = null; } public void update(Connection connection, String hint) { final Set<DatabaseObject> expandedNodes = new HashSet<DatabaseObject>(); // if this update is for the currently visible connection in the model, // cache the set of expanded nodes for replay if (objects_ != null && connection == connection_) { TreeNode rootNode = objects_.getRootTreeNode(); if (!objects_.getRootTreeNode().isDestroyed()) { for (int i = 0; i < rootNode.getChildCount(); i++) { if (rootNode.isChildOpen(i)) { DatabaseObject node = (DatabaseObject)rootNode.getChildValue(i); expandedNodes.add(node); } } } } // create tables model and widget objectsModel_ = new ObjectBrowserModel(); // capture scroll position final int scrollPosition = scrollPanel_.getVerticalScrollPosition(); // update the table then restore expanded nodes objectsModel_.update( connection, // connection expandedNodes, new Command() { // table update completed, expand nodes @Override public void execute() { TreeNode rootNode = objects_.getRootTreeNode(); if (!rootNode.isDestroyed()) { for (int i = 0; i < rootNode.getChildCount(); i++) { final DatabaseObject nodeVal = (DatabaseObject)(rootNode.getChildValue(i)); for (DatabaseObject expanded: expandedNodes) { if (expanded.isEqualTo(nodeVal)) rootNode.setChildOpen(i, true, false); } } } } }, new Command() { // node expansion completed, restore scroll position @Override public void execute() { // delay 100ms to allow expand animation to complete new Timer() { @Override public void run() { scrollPanel_.setVerticalScrollPosition(scrollPosition); } }.schedule(100); } }); // create new widget objects_ = new CellTree(objectsModel_, null, RES, MESSAGES); // create the top level list of objects objects_.setDefaultNodeSize(Integer.MAX_VALUE); objects_.getElement().getStyle().setBorderStyle(BorderStyle.NONE); objects_.setWidth("100%"); // wrap in vertical panel to get correct scrollbar behavior VerticalPanel verticalWrapper = new VerticalPanel(); verticalWrapper.setWidth("100%"); verticalWrapper.add(objects_); scrollPanel_.setWidget(verticalWrapper); // cache connection connection_ = connection; } @Override public void onResize() { } public interface Resources extends CellTree.Resources { @Source("zoomDataset_2x.png") ImageResource zoomDataset2x(); @ImageOptions(flipRtl = true) @Source("ExpandIcon_2x.png") ImageResource cellTreeClosedItem(); /** * An image indicating that a node is loading. */ @ImageOptions(flipRtl = true) @Source("progress.gif") ImageResource cellTreeLoading(); @ImageOptions(flipRtl = true) @Source("CollapseIcon_2x.png") ImageResource cellTreeOpenItem(); @Source({CellTree.Style.DEFAULT_CSS, "TableBrowser.css"}) public Style cellTreeStyle(); public interface Style extends CellTree.Style { String fieldName(); String fieldType(); String tableViewDataset(); String containerIcon(); } } static final Resources RES = GWT.create(Resources.class); static { RES.cellTreeStyle().ensureInjected(); } @DefaultLocale("en_US") public interface TableBrowserMessages extends CellTreeMessages { @DefaultMessage("Show more") String showMore(); @DefaultMessage("(No tables)") String emptyTree(); } private static final TableBrowserMessages MESSAGES = GWT.create(TableBrowserMessages.class); private final ScrollPanel scrollPanel_; private CellTree objects_; private ObjectBrowserModel objectsModel_; private Connection connection_; }