// 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.history.Place;
import com.google.collide.client.util.PathUtil;
import com.google.collide.client.workspace.FileTreeModel;
import com.google.collide.client.workspace.FileTreeNode;
import com.google.collide.json.shared.JsonArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
/**
* A controller whose sole responsibility it is to listen for changes on the
* file tree model and reload the editor contents when a relevant change occurs.
*
*/
public class EditorReloadingFileTreeListener implements FileTreeModel.TreeModelChangeListener {
public static EditorReloadingFileTreeListener create(
Place currentPlace, EditorBundle editorBundle, FileTreeModel fileTreeModel) {
EditorReloadingFileTreeListener listener =
new EditorReloadingFileTreeListener(currentPlace, editorBundle, fileTreeModel);
fileTreeModel.addModelChangeListener(listener);
return listener;
}
private final Place currentPlace;
private final EditorBundle editorBundle;
private final FileTreeModel fileTreeModel;
private EditorReloadingFileTreeListener(
Place currentPlace, EditorBundle editorBundle, FileTreeModel fileTreeModel) {
this.currentPlace = currentPlace;
this.editorBundle = editorBundle;
this.fileTreeModel = fileTreeModel;
}
public void cleanup() {
fileTreeModel.removeModelChangeListener(this);
}
@Override
public void onNodeAdded(PathUtil parentDirPath, FileTreeNode newNode) {
}
@Override
public void onNodeMoved(
PathUtil oldPath, FileTreeNode node, PathUtil newPath, FileTreeNode newNode) {
// if the moved node is currently open in the editor, or is a dir that is
// somewhere in the path of whatever is open in the editor, then fix the
// breadcrumbs
PathUtil editorPath = editorBundle.getBreadcrumbs().getPath();
if (editorPath == null) {
return;
}
if (oldPath.containsPath(editorPath)) {
// replace the start of the editor's path with the node's new path
final PathUtil newEditorPath = PathUtil.concatenate(newPath,
PathUtil.createExcludingFirstN(editorPath, oldPath.getPathComponentsCount()));
editorBundle.getBreadcrumbs().setPath(newEditorPath);
// Wait until DocumentManagerFileTreeModelListener updates the path in the document.
Scheduler.get().scheduleFinally(new ScheduledCommand() {
@Override
public void execute() {
currentPlace.fireChildPlaceNavigation(
FileSelectedPlace.PLACE.createNavigationEvent(newEditorPath));
}
});
}
}
@Override
public void onNodesRemoved(JsonArray<FileTreeNode> oldNodes) {
// do nothing
}
@Override
public void onNodeReplaced(FileTreeNode oldNode, FileTreeNode newNode) {
if (oldNode == null || !isRelevantPath(oldNode.getNodePath())) {
return;
}
/*
* TODO: If we synchronously fire the place
* navigation, eventually we get into a state where the FileTree attempts to
* autoselect the node, but fails with an assertion error (rushing, so no
* time to investigate right now)
*/
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
// Reload the file
currentPlace.fireChildPlaceNavigation(
FileSelectedPlace.PLACE.createNavigationEvent(editorBundle.getPath(),
FileSelectedPlace.NavigationEvent.IGNORE_LINE_NUMBER,
FileSelectedPlace.NavigationEvent.IGNORE_COLUMN, true));
}
});
}
private boolean isRelevantPath(PathUtil changePath) {
PathUtil editorPath = editorBundle.getPath();
return editorPath != null && changePath.containsPath(editorPath);
}
}