blob: 70267358cfcf8f7fcbac9f0cc4d88e179859cb69 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Remain Software
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* wim.jongman@remainsoftware.com - initial API and implementation
*******************************************************************************/
package org.eclipse.tips.ide.internal;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.tips.core.ITipManager;
import org.eclipse.tips.core.Tip;
import org.eclipse.tips.core.TipProvider;
import org.eclipse.tips.core.internal.LogUtil;
import org.eclipse.tips.core.internal.TipManager;
import org.eclipse.tips.ui.internal.DefaultTipManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.services.IEvaluationService;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Class to manage the tip providers and start the tip of the day UI.
*/
@SuppressWarnings("restriction")
public class IDETipManager extends DefaultTipManager {
private TipSourceProvider fSourceProvider = new TipSourceProvider();
private List<Integer> fReadTips = new ArrayList<>();
private boolean fNewTips;
private boolean fSourceProviderAdded;
private static IDETipManager instance = new IDETipManager();
/**
* @return the tip manager instance.
*/
public static synchronized ITipManager getInstance() {
if (instance.isDisposed()) {
instance = new IDETipManager();
}
return instance;
}
private IDETipManager() {
}
@Override
public ITipManager register(TipProvider provider) {
super.register(provider);
load(provider);
return this;
}
private void load(TipProvider provider) {
Job job = new Job("Loading " + provider.getDescription()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
return provider.loadNewTips(monitor);
}
};
job.addJobChangeListener(new ProviderLoadJobChangeListener(this, provider));
job.schedule();
}
@Override
public ITipManager open(boolean startUp) {
if (isOpen()) {
return this;
}
if (!fSourceProviderAdded) {
IEvaluationService evaluationService = PlatformUI.getWorkbench().getService(IEvaluationService.class);
evaluationService.addSourceProvider(fSourceProvider);
fSourceProviderAdded = true;
}
fReadTips.addAll(Preferences.loadReadState());
return super.open(startUp);
}
/**
* Saves the tip read status to disk.
*
* @param pReadTips the tips to save
*
*/
private void saveReadState(List<Integer> pReadTips) {
Job job = new Job("Tips save read state..") {
@Override
protected IStatus run(IProgressMonitor monitor) {
SubMonitor subMonitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
subMonitor.setTaskName("Saving read tips..");
IStatus status = Preferences.saveReadState(pReadTips);
subMonitor.done();
return status;
}
};
job.schedule();
}
/**
* Calculates the new tip count to find if we need to expose the status trim
* tool item.
*
* @param newTips
*/
private void refreshUI() {
boolean newTips = getProviders().stream().filter(p -> !p.getTips().isEmpty()).count() > 0;
Job job = new Job("Tips status bar refresh..") {
@Override
protected IStatus run(IProgressMonitor monitor) {
setNewTips(newTips);
return Status.OK_STATUS;
}
};
job.schedule();
}
@Override
public boolean isRunAtStartup() {
return Preferences.isRunAtStartup();
}
@Override
public TipManager setRunAtStartup(boolean runAtStartup) {
Preferences.setRunAtStartup(runAtStartup);
return this;
}
@Override
public boolean mustServeReadTips() {
return Preferences.isServeReadTips();
}
@Override
public TipManager setServeReadTips(boolean serveRead) {
Preferences.setServeReadTips(serveRead);
return this;
}
@Override
public ITipManager log(IStatus status) {
if (status.matches(IStatus.ERROR | IStatus.WARNING)) {
Bundle bundle = FrameworkUtil.getBundle(getClass());
Platform.getLog(bundle).log(status);
}
if (System.getProperty("org.eclipse.tips.consolelog") != null) {
System.out.println(status.toString());
}
return this;
}
@Override
public boolean isRead(Tip tip) {
if (fReadTips.contains(Integer.valueOf(tip.hashCode()))) {
return true;
}
return false;
}
@Override
public TipManager setAsRead(Tip tip) {
if (!isRead(tip)) {
fReadTips.add(Integer.valueOf(tip.hashCode()));
}
return this;
}
protected synchronized IDETipManager setNewTips(boolean newTips) {
if (fNewTips != newTips) {
fNewTips = newTips;
fSourceProvider.setStatus(fNewTips);
}
return this;
}
@Override
public void dispose() {
try {
refreshUI();
saveReadState(Collections.unmodifiableList(fReadTips));
} finally {
super.dispose();
}
}
/**
* {@inheritDoc}
* <p>
* The weight is determined by the enablement expression. If there is no
* enablement expression then the weight is 20. If there is a non matching
* enablement then the weight is 30. If there is a matching enablement then the
* weight is 10.
*
* @param provider the provider
*
* @return the weight
*/
@Override
public int getPriority(TipProvider provider) {
log(LogUtil.info("Evaluating expression: " + provider.getExpression()));
int priority = doGetPriority(provider.getExpression());
log(LogUtil.info("Evaluating expression done. Priority: " + priority));
return priority;
}
private int doGetPriority(String expression) {
if (expression == null) {
return 20;
}
try {
String myExpression = "<enablement>" + expression + "</enablement>";
myExpression = "<?xml version=\"1.0\"?>" + myExpression;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = factory.newDocumentBuilder().parse(new ByteArrayInputStream(myExpression.getBytes()));
Element element = (Element) doc.getElementsByTagName("enablement").item(0);
Expression expressionObj = ExpressionConverter.getDefault().perform(element);
final EvaluationResult result = expressionObj.evaluate(getEvaluationContext());
if (result == EvaluationResult.TRUE) {
return 10;
} else {
return 30;
}
} catch (Exception e) {
log(LogUtil.error(e));
return 20;
}
}
/**
*
* @return Evaluation Context to evaluate core expression
*/
private static IEvaluationContext getEvaluationContext() {
IEvaluationService evalService = PlatformUI.getWorkbench().getService(IEvaluationService.class);
IEvaluationContext currentState = evalService.getCurrentState();
return currentState;
}
}