Package com.google.collide.client.code

Source Code of com.google.collide.client.code.CodePanelBundle

// 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.AppContext;
import com.google.collide.client.code.FileSelectionController.FileOpenedEvent;
import com.google.collide.client.code.errorrenderer.EditorErrorListener;
import com.google.collide.client.collaboration.IncomingDocOpDemultiplexer;
import com.google.collide.client.document.DocumentManager;
import com.google.collide.client.editor.Editor.DocumentListener;
import com.google.collide.client.history.Place;
import com.google.collide.client.history.PlaceNavigationEvent;
import com.google.collide.client.search.FileNameSearch;
import com.google.collide.client.search.SearchPlace;
import com.google.collide.client.search.SearchPlaceNavigationHandler;
import com.google.collide.client.search.awesomebox.AwesomeBoxContext;
import com.google.collide.client.search.awesomebox.FileNameNavigationSection;
import com.google.collide.client.search.awesomebox.GotoActionSection;
import com.google.collide.client.search.awesomebox.OutlineViewAwesomeBoxSection;
import com.google.collide.client.search.awesomebox.PrimaryWorkspaceActionSection;
import com.google.collide.client.search.awesomebox.PrimaryWorkspaceActionSection.FindActionSelectedCallback;
import com.google.collide.client.search.awesomebox.components.FindReplaceComponent;
import com.google.collide.client.search.awesomebox.components.FindReplaceComponent.FindMode;
import com.google.collide.client.search.awesomebox.host.AwesomeBoxComponentHost.AwesomeBoxComponentHiddenListener;
import com.google.collide.client.util.PathUtil;
import com.google.collide.client.util.dom.eventcapture.GlobalHotKey;
import com.google.collide.client.workspace.FileTreeModel;
import com.google.collide.client.workspace.FileTreeNodeMoveController;
import com.google.collide.client.workspace.WorkspacePlace;
import com.google.collide.client.workspace.WorkspaceShell;
import com.google.collide.client.workspace.outline.OutlineModel;
import com.google.collide.client.workspace.outline.OutlineSection;
import com.google.collide.dto.GetWorkspaceMetaDataResponse;
import com.google.collide.shared.document.Document;
import com.google.common.base.Preconditions;
import com.google.gwt.core.client.Scheduler;

import org.waveprotocol.wave.client.common.util.SignalEvent;

import elemental.html.Element;

/**
* Dependencies and Presenter setup code for everything under the workspace header involved with
* code editing.
*/
/*
* TODO: Some cleanup in here now that the this class is created and invoked synchronously.
* Particularly lets extract the AwesomeBox cruft and see if anything else makes sense to bundle
* together into a separate class.
*/
public class CodePanelBundle {

  // Dependencies passed in at Handler construction time.
  private final AppContext appContext;
  private final WorkspaceShell shell;
  private final FileTreeModel fileTreeModel;
  private final DocumentManager documentManager;
  private final ParticipantModel participantModel;
  private final IncomingDocOpDemultiplexer docOpReceiver;

  // AwesomeBox Related
  public final FileNameSearch searchIndex;
  public final AwesomeBoxContext awesomeBoxCodeContext;
  private final FileNameNavigationSection fileNavSection;
  private final PrimaryWorkspaceActionSection primaryWorkspaceActionsSection;
  private final GotoActionSection gotoActionSection;
  private final OutlineViewAwesomeBoxSection outlineViewAwesomeBoxSection;
  private final WorkspacePlace workspacePlace;


  // AwesomeBox Components
  private final FindReplaceComponent findReplaceComponent;

  // Presenters and Controllers that require cleanup.
  private EditorBundle editorBundle;
  private EditorReloadingFileTreeListener editorReloadingFileTreeListener;
  private NoFileSelectedPanel welcomePanel;
  private FileSelectionController fileSelectionController;
  private FileTreeNodeMoveController treeNodeMoveController;
  private FileTreeSection fileTreeSection;
  private EditableContentArea contentArea;

  public CodePanelBundle(AppContext appContext,
      WorkspaceShell shell,
      FileTreeModel fileTreeModel,
      FileNameSearch searchIndex,
      DocumentManager documentManager,
      ParticipantModel participantModel,
      IncomingDocOpDemultiplexer docOpReceiver,
      WorkspacePlace workspacePlace) {
    this.appContext = appContext;
    this.shell = shell;
    this.fileTreeModel = fileTreeModel;
    this.searchIndex = searchIndex;
    this.documentManager = documentManager;
    this.participantModel = participantModel;
    this.docOpReceiver = docOpReceiver;
    this.workspacePlace = workspacePlace;

    awesomeBoxCodeContext = new AwesomeBoxContext(new AwesomeBoxContext.Builder().setWaterMarkText(
        "Type to find files and use actions").setPlaceholderText("Actions"));
    fileNavSection = new FileNameNavigationSection(appContext.getResources(), searchIndex);
    primaryWorkspaceActionsSection = new PrimaryWorkspaceActionSection(appContext.getResources());
    gotoActionSection = new GotoActionSection(appContext.getResources());
    outlineViewAwesomeBoxSection = new OutlineViewAwesomeBoxSection(appContext.getResources());

    // Special Components
    findReplaceComponent =
        new FindReplaceComponent(new FindReplaceComponent.View(appContext.getResources()));

    initializeAwesomeBoxContext();
  }

  private void initializeAwesomeBoxContext() {
    primaryWorkspaceActionsSection.getFindActionSelectionListener()
        .add(new FindActionSelectedCallback() {
          @Override
          public void onSelected(FindMode mode) {
            findReplaceComponent.setFindMode(mode);
            appContext.getAwesomeBoxComponentHostModel().setActiveComponent(findReplaceComponent);
            shell.getHeader().getAwesomeBoxComponentHost().show();
          }
        });

    awesomeBoxCodeContext.addSection(outlineViewAwesomeBoxSection);
    awesomeBoxCodeContext.addSection(fileNavSection);
    awesomeBoxCodeContext.addSection(gotoActionSection);
    awesomeBoxCodeContext.addSection(primaryWorkspaceActionsSection);
  }

  public void cleanup() {
    editorReloadingFileTreeListener.cleanup();
    editorBundle.cleanup();
    if (welcomePanel != null) {
      welcomePanel.detach();
    }
    treeNodeMoveController.cleanup();
    fileTreeSection.cleanup();

    GlobalHotKey.unregister(appContext.getKeyBindings().localFind());
    GlobalHotKey.unregister(appContext.getKeyBindings().localReplace());
    GlobalHotKey.unregister(appContext.getKeyBindings().gotoLine());
    GlobalHotKey.unregister(appContext.getKeyBindings().snapshot());
  }

  public void attach() {
    // Construct the Root View for the CodePerspective.
    CodePerspective.Resources res = appContext.getResources();
    CodePerspective.View codePerspectiveView = new CodePerspective.View(res);

    // Then create all the Presenters.
    OutlineModel outlineModel = new OutlineModel();
    editorBundle = EditorBundle.create(appContext,
        workspacePlace,
        documentManager,
        participantModel,
        outlineModel,
        fileTreeModel,
        EditorErrorListener.NOOP_ERROR_RECEIVER);

    UneditableDisplay uneditableDisplay = UneditableDisplay.create(new UneditableDisplay.View(res));

    // AwesomeBox Section Setup
    appContext.getAwesomeBoxModel().changeContext(awesomeBoxCodeContext);
    outlineViewAwesomeBoxSection.setOutlineModelAndEditor(outlineModel, editorBundle.getEditor());
    registerAwesomeBoxEvents();

    editorReloadingFileTreeListener =
        EditorReloadingFileTreeListener.create(workspacePlace, editorBundle, fileTreeModel);

    fileTreeSection = FileTreeSection.create(
        workspacePlace, appContext, fileTreeModel, editorBundle.getDebuggingModelController());
    fileTreeSection.getTree().renderTree(0);

    // TODO: The term "Section" is overloaded here. It
    // conflates the NavigationSection (the File Tree and the Conflict List)
    // with panels in the NavigationToolBar. The Collab and Outline Sections
    // here are actually panels on the NavigationToolBar. Clean this up.

    CollaborationSection collabSection = CollaborationSection.create(
        new CollaborationSection.View(res), participantModel, appContext);

    treeNodeMoveController = new FileTreeNodeMoveController(
        appContext, fileTreeSection.getFileTreeUiController(), fileTreeModel);

    OutlineSection outlineSection = OutlineSection.create(
        new OutlineSection.View(res), appContext, outlineModel,
        editorBundle.getOutlineController());

    final WorkspaceNavigationToolBar navigationToolBar = WorkspaceNavigationToolBar.create(
        codePerspectiveView.getNavigationView().getNavigationToolBarView(), collabSection,
        outlineSection);

    WorkspaceNavigation workspaceNavigation = WorkspaceNavigation.create(
        codePerspectiveView.getNavigationView(),
        new WorkspaceNavigationSection[] {fileTreeSection},
        new WorkspaceNavigationSection[] {collabSection, outlineSection}, navigationToolBar);
    navigationToolBar.setWorkspaceNavigation(workspaceNavigation);

    contentArea =
        EditableContentArea.create(codePerspectiveView.getContentView(), appContext, editorBundle);

    CodePerspective codePerspective = CodePerspective.create(
        codePerspectiveView, workspacePlace, workspaceNavigation, contentArea, appContext);

    // Connect views to the DOM.
    Element rightSidebarContentContainer = codePerspectiveView.getSidebarElement();
    rightSidebarContentContainer.appendChild(
        editorBundle.getDebuggingModelController().getDebuggingSidebarElement());
    shell.setPerspective(codePerspectiveView.getElement());

    fileSelectionController = new FileSelectionController(documentManager,
        editorBundle,
        uneditableDisplay,
        fileTreeModel,
        fileTreeSection.getFileTreeUiController(),
        contentArea);

    // Creates the welcome panel
    welcomePanel = NoFileSelectedPanel.create(workspacePlace, appContext.getResources());

    // Register navigation handler for FileSelection.
    FileSelectedPlaceNavigationHandler fileSelectionHandler =
        new FileSelectedPlaceNavigationHandler(appContext,
            codePerspective,
            fileSelectionController,
            contentArea);
    workspacePlace.registerChildHandler(FileSelectedPlace.PLACE, fileSelectionHandler);

    // Register navigation handler for searching within files.
    SearchPlaceNavigationHandler searchHandler = new SearchPlaceNavigationHandler(appContext,
        contentArea, fileTreeSection.getFileTreeUiController(), workspacePlace);
    workspacePlace.registerChildHandler(SearchPlace.PLACE, searchHandler);
  }

  public void enterWorkspace(final PlaceNavigationEvent<? extends Place> navigationEvent,
      final GetWorkspaceMetaDataResponse metadata) {
    if (!navigationEvent.isActiveLeaf()) {
      return;
    }

    // If there are no previously open files, show the welcome
    // panel.
    if (metadata.getLastOpenFiles().size() == 0) {
      showNoFileSelectedPanel();
      return;
    }

    Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
      @Override
      public void execute() {
        // we check the very first file since that's all we support right now
        String file = metadata.getLastOpenFiles().get(0);
        Preconditions.checkNotNull(file, "Somehow the file to navigate to was null");

        PlaceNavigationEvent<FileSelectedPlace> event =
            FileSelectedPlace.PLACE.createNavigationEvent(new PathUtil(file));
        navigationEvent.getPlace().fireChildPlaceNavigation(event);
      }
    });
  }

  public void showNoFileSelectedPanel() {
    editorBundle.getBreadcrumbs().clearPath();
    contentArea.setContent(welcomePanel, false);
  }

  /**
   * Register's events that the AwesomeBox context uses.
   */
  private void registerAwesomeBoxEvents() {
    // If these fail someone called the registerAwesomeBoxEvents method
    // to early in enterPlace. Lets notify them clearly.
    Preconditions.checkArgument(
        editorBundle != null, "Editor must be created before registering awesome box events.");

    // Register Hiding Listener
    shell.getHeader().getAwesomeBoxComponentHost().getComponentHiddenListener()
        .add(new AwesomeBoxComponentHiddenListener() {
          @Override
          public void onHidden(Reason reason) {
            if (reason != Reason.OTHER) {
              editorBundle.getEditor().getFocusManager().focus();
            }
          }
        });

    // Attach the editor to the editorActionSection
    gotoActionSection.attachEditorAndPlace(workspacePlace, editorBundle.getEditor());

    // We register the file opened events.
    fileNavSection.registerOnFileOpenedHandler(workspacePlace);
    primaryWorkspaceActionsSection.registerOnFileOpenedHandler(workspacePlace);
    workspacePlace.registerSimpleEventHandler(FileOpenedEvent.TYPE, new FileOpenedEvent.Handler() {
      @Override
      public void onFileOpened(boolean isEditable, PathUtil filePath) {
        shell.getHeader().getAwesomeBoxComponentHost().hide();
      }
    });

    // Hook find/replace upto the editor.
    editorBundle.getEditor().getDocumentListenerRegistrar().add(new DocumentListener() {
      @Override
      public void onDocumentChanged(Document oldDocument, Document newDocument) {
        findReplaceComponent.attachEditor(editorBundle.getEditor());
      }
    });

    // Register any hotkeys
    GlobalHotKey.Handler findAndReplaceHandler = new GlobalHotKey.Handler() {
      @Override
      public void onKeyDown(SignalEvent event) {
        if (fileSelectionController.isSelectedFileEditable()) {
          findReplaceComponent.setFindMode(event.getShiftKey() ? FindMode.REPLACE : FindMode.FIND);

          String selectedText = editorBundle.getEditor().getSelection().getSelectedText();
          boolean isFindActive = findReplaceComponent.isActive();
          boolean shouldReplaceIfInFindMode = isFindActive && !selectedText.isEmpty();

          // TODO: Check the AB query once it exists
          // && !abQuery.isEmpty();
          boolean shouldReplaceIfNotInFindMode = !isFindActive && !selectedText.isEmpty();

          if (shouldReplaceIfInFindMode || shouldReplaceIfNotInFindMode) {
            findReplaceComponent.setQuery(selectedText);
          }
          appContext.getAwesomeBoxComponentHostModel().setActiveComponent(findReplaceComponent);
        }
        shell.getHeader().getAwesomeBoxComponentHost().show();
      }
    };
    GlobalHotKey.register(
        appContext.getKeyBindings().localFind(), findAndReplaceHandler, "local find");
    GlobalHotKey.register(
        appContext.getKeyBindings().localReplace(), findAndReplaceHandler, "local replace");
    GlobalHotKey.register(appContext.getKeyBindings().gotoLine(), new GlobalHotKey.Handler() {
      @Override
      public void onKeyDown(SignalEvent event) {
        // TODO: Make a component which handles goto only.
        shell.getHeader().getAwesomeBoxComponentHost().show();
      }
    }, "goto line");
  }
}
TOP

Related Classes of com.google.collide.client.code.CodePanelBundle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.