/*
* Copyright (c) 2014, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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.dart.tools.ui.internal.text.dart;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.dart.server.generated.AnalysisServer;
import org.dartlang.analysis.server.protocol.AnalysisService;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Helper for updating the order in which files are analyzed in contexts associated with editors.
* This is called once per instantiated editor on startup and then once for each editor as it
* becomes active. For example, if there are 2 of 7 editors visible on startup, then this will be
* called for the 2 visible editors.
*
* @coverage dart.editor.ui.text
*/
public class DartPriorityFilesHelper_NEW {
private final IWorkbench workbench;
private final AnalysisServer analysisServer;
private final Object lock = new Object();
private final Map<String, List<String>> subscriptions = Maps.newHashMap();
private final List<String> visibleFiles = Lists.newArrayList();
private List<String> visibleFilesSent = Lists.newArrayList();
private final Job sendToServerJob = new Job("Send visible files subscriptions") {
@Override
protected IStatus run(IProgressMonitor monitor) {
synchronized (lock) {
// send priority files, if changed
if (!visibleFiles.equals(visibleFilesSent)) {
analysisServer.analysis_setPriorityFiles(visibleFiles);
visibleFilesSent = Lists.newArrayList(visibleFiles);
}
// update visible file subscriptions
subscriptions.put(AnalysisService.HIGHLIGHTS, visibleFiles);
subscriptions.put(AnalysisService.NAVIGATION, visibleFiles);
subscriptions.put(AnalysisService.OCCURRENCES, visibleFiles);
subscriptions.put(AnalysisService.OUTLINE, visibleFiles);
subscriptions.put(AnalysisService.OVERRIDES, visibleFiles);
if (analysisServer != null) {
analysisServer.analysis_setSubscriptions(subscriptions);
}
// done
test_hasPendingJob = false;
}
return Status.OK_STATUS;
}
};
private boolean test_hasPendingJob = false;
public DartPriorityFilesHelper_NEW(IWorkbench workbench, AnalysisServer analysisServer) {
this.workbench = workbench;
this.analysisServer = analysisServer;
}
/**
* Schedules helper start, once {@link IWorkbenchPage} is created.
*/
public void start() {
workbench.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
internalStart(page);
}
}
}
});
}
/**
* Waits until a scheduled background job for sending information to the server finishes, so that
* test can check correctness of the information.
*/
public void test_waitWhileHasPendingJob() {
while (true) {
synchronized (lock) {
if (!test_hasPendingJob) {
return;
}
}
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.MILLISECONDS);
}
}
/**
* @return the {@link DartPriorityFileEditor} that corresponds to the given {@link IWorkbenchPart}
* , maybe {@code null}.
*/
private DartPriorityFileEditor getPriorityFileEditor(IWorkbenchPart part) {
if (part != null) {
Object maybeEditor = part.getAdapter(DartPriorityFileEditor.class);
if (maybeEditor instanceof DartPriorityFileEditor) {
return (DartPriorityFileEditor) maybeEditor;
}
}
return null;
}
/**
* Answer the visible {@link DartPriorityFileEditor}s.
*/
private List<DartPriorityFileEditor> getVisibleEditors() {
List<DartPriorityFileEditor> editors = Lists.newArrayList();;
for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) {
for (IWorkbenchPage page : window.getPages()) {
for (IEditorReference editorRef : page.getEditorReferences()) {
IEditorPart part = editorRef.getEditor(false);
DartPriorityFileEditor editor = getPriorityFileEditor(part);
if (editor != null) {
if (editor.isVisible()) {
editors.add(editor);
}
}
}
}
}
return editors;
}
/**
* Starts listening for {@link IWorkbenchPage} and adding/removing files of the visible editors.
*/
private void internalStart(IWorkbenchPage activePage) {
// make files of the currently visible editors a priority ones
prepareVisibleFiles();
// schedule job to send an initial state
test_hasPendingJob = true;
sendToServerJob.schedule();
// track visible editors
activePage.addPartListener(new IPartListener2() {
@Override
public void partActivated(IWorkbenchPartReference partRef) {
}
@Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {
}
@Override
public void partClosed(IWorkbenchPartReference partRef) {
}
@Override
public void partDeactivated(IWorkbenchPartReference partRef) {
}
@Override
public void partHidden(IWorkbenchPartReference partRef) {
if (isDartPriorityFileEditor(partRef)) {
scheduleSubscriptionsUpdate();
}
}
@Override
public void partInputChanged(IWorkbenchPartReference partRef) {
if (isDartPriorityFileEditor(partRef)) {
scheduleSubscriptionsUpdate();
}
}
@Override
public void partOpened(IWorkbenchPartReference partRef) {
}
@Override
public void partVisible(IWorkbenchPartReference partRef) {
if (isDartPriorityFileEditor(partRef)) {
scheduleSubscriptionsUpdate();
}
}
});
}
private boolean isDartPriorityFileEditor(IWorkbenchPartReference partRef) {
if (partRef == null) {
return false;
}
// get part
IWorkbenchPart part = partRef.getPart(false);
if (part == null) {
return false;
}
// get editor
DartPriorityFileEditor editor = getPriorityFileEditor(part);
return editor != null;
}
/**
* Fills {@link #visibleFiles} with visible files.
*/
private void prepareVisibleFiles() {
visibleFiles.clear();
List<DartPriorityFileEditor> editors = getVisibleEditors();
for (DartPriorityFileEditor editor : editors) {
String file = editor.getInputFilePath();
if (file != null) {
visibleFiles.add(file);
}
}
}
/**
* Prepares the list of visible files and a schedules subscription update.
*/
private void scheduleSubscriptionsUpdate() {
synchronized (lock) {
prepareVisibleFiles();
test_hasPendingJob = true;
sendToServerJob.schedule(25);
}
}
}