// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.code;
import com.google.collide.client.util.CssUtils;
import com.google.collide.client.util.Elements;
import com.google.collide.client.util.ResizeController;
import com.google.collide.client.util.ResizeController.ResizeProperty;
import com.google.collide.client.workspace.outline.OutlineSection;
import com.google.collide.mvp.CompositeView;
import com.google.collide.mvp.UiComponent;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiTemplate;
/**
* The navigation area for the workspace Shell.
*/
public class WorkspaceNavigation extends UiComponent<WorkspaceNavigation.View> {
/**
* Static factory method for obtaining an instance of the WorkspaceNavigation.
*/
public static WorkspaceNavigation create(View view, WorkspaceNavigationSection<?>[] topSections,
WorkspaceNavigationSection<?>[] bottomSections,
WorkspaceNavigationToolBar navigationToolBar) {
WorkspaceNavigation workspaceNavigation = new WorkspaceNavigation(view, navigationToolBar);
for (WorkspaceNavigationSection<?> topSection : topSections) {
workspaceNavigation.addTopSection(topSection);
}
for (WorkspaceNavigationSection<?> bottomSection : bottomSections) {
bottomSection.setVisible(false);
workspaceNavigation.addBottomSection(bottomSection);
}
return workspaceNavigation;
}
/**
* Style names for this presenter's view.
*/
public interface Css extends CssResource {
/**
* Returns the height of the bottom section.
*/
String bottomSectionsHeight();
String root();
String topSections();
String bottomSections();
String bottomSectionsClosed();
String bottomSectionsAnimator();
String bottomSectionsContent();
String splitter();
}
/**
* CSS and images used by this presenter.
*/
interface Resources
extends
FileTreeSection.Resources,
CollaborationSection.Resources,
OutlineSection.Resources,
WorkspaceNavigationToolBar.Resources,
ResizeController.Resources {
@Source({"com/google/collide/client/common/constants.css", "WorkspaceNavigation.css"})
Css workspaceNavigationCss();
}
/**
* View for this presenter that happens to be a simple overlay type.
*/
public static class View extends CompositeView<Void> {
@UiTemplate("WorkspaceNavigation.ui.xml")
interface MyBinder extends UiBinder<com.google.gwt.dom.client.DivElement, View> {
}
private static MyBinder binder = GWT.create(MyBinder.class);
@UiField(provided = true)
final Css css;
@UiField
DivElement topSections;
@UiField
DivElement splitter;
@UiField
DivElement bottomSections;
@UiField
DivElement bottomSectionsAnimator;
@UiField
DivElement bottomSectionsContent;
@UiField
DivElement toolbarHolder;
WorkspaceNavigationToolBar.View navigationToolBarView;
protected View(Resources res) {
this.css = res.workspaceNavigationCss();
this.navigationToolBarView = new WorkspaceNavigationToolBar.View(res);
setElement(Elements.asJsElement(binder.createAndBindUi(this)));
setBottomSectionsVisible(false);
Elements.asJsElement(toolbarHolder).appendChild(navigationToolBarView.getElement());
/*
* Add a resize controller. We set the default value programatically
* because we use padding, which skews the height calculations in
* ResizeController.
*/
// TODO: Move this to the presenter.
ResizeController splitterController =
new ResizeController(res, Elements.asJsElement(splitter),
new ResizeController.ElementInfo(Elements.asJsElement(bottomSections),
ResizeProperty.HEIGHT, css.bottomSectionsHeight()),
new ResizeController.ElementInfo(Elements.asJsElement(bottomSectionsAnimator),
ResizeProperty.HEIGHT, css.bottomSectionsHeight()),
new ResizeController.ElementInfo(Elements.asJsElement(bottomSectionsContent),
ResizeProperty.HEIGHT, css.bottomSectionsHeight()));
splitterController.setNegativeDelta(true);
splitterController.start();
}
public WorkspaceNavigationToolBar.View getNavigationToolBarView() {
return navigationToolBarView;
}
private void setBottomSectionsVisible(boolean isVisible) {
// Use a CSS class to set the height to 0px so we don't override the
// height attribute set by the resize controller.
CssUtils.setClassNameEnabled(Elements.asJsElement(bottomSections), css.bottomSectionsClosed(),
!isVisible);
CssUtils.setClassNameEnabled(Elements.asJsElement(bottomSectionsAnimator),
css.bottomSectionsClosed(), !isVisible);
CssUtils.setDisplayVisibility2(Elements.asJsElement(splitter), isVisible);
}
}
/**
* The bottom section that is currently visible.
*/
private WorkspaceNavigationSection<?> shownBottomSection;
/**
* The bottom section that was previously visible, and may need to be hidden
* when a new section is shown. We don't hide the old section while it is
* animating out of view, so we need to keep track of it even if it isn't
* logically selected.
*/
private WorkspaceNavigationSection<?> previouslyShownBottomSection;
private final WorkspaceNavigationToolBar navigationToolBar;
WorkspaceNavigation(View view, WorkspaceNavigationToolBar navigationToolBar) {
super(view);
this.navigationToolBar = navigationToolBar;
// Hide the bottom sections by default.
showBottomSection(null);
}
/**
* Takes in a {@link WorkspaceNavigationSection} and adds it to the top
* sections.
*
* @param section section to add
*/
void addTopSection(WorkspaceNavigationSection<?> section) {
Elements.asJsElement(getView().topSections).appendChild(section.getView().getElement());
}
/**
* Takes in a {@link WorkspaceNavigationSection} and adds it to the bottom
* sections.
*
* @param section section to add
*/
void addBottomSection(WorkspaceNavigationSection<?> section) {
Elements.asJsElement(getView().bottomSectionsContent)
.appendChild(section.getView().getElement());
}
/**
* Hide currently shown navigation section and show the given one.
*
* @param section section to show, or {@code null} to hide shown section
*/
void showBottomSection(WorkspaceNavigationSection<?> section) {
if (section == shownBottomSection) {
return;
}
/*
* Hide the old section, but only if something else if going to be shown.
* Otherwise, we want to animate the old section out of view.
*/
if (previouslyShownBottomSection != null && section != null) {
previouslyShownBottomSection.setVisible(false);
previouslyShownBottomSection = null;
}
if (section != null) {
section.setVisible(true);
previouslyShownBottomSection = section;
}
getView().setBottomSectionsVisible(section != null);
shownBottomSection = section;
}
/**
* Shows the specified section if it is not visible, or hides the section if
* it is visible.
*
* @return true if the section is now showing, false if not
*/
boolean toggleBottomSection(WorkspaceNavigationSection<?> section) {
if (section == shownBottomSection) {
showBottomSection(null);
return false;
} else {
showBottomSection(section);
return true;
}
}
}