/*******************************************************************************
* Copyright (c) 2011, 2014 Wind River Systems, Inc. and others. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.ui.trees;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.tcf.te.core.interfaces.IViewerInput;
import org.eclipse.tcf.te.ui.activator.UIPlugin;
import org.eclipse.tcf.te.ui.nls.Messages;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.XMLMemento;
/**
* The tree viewer action manager used to provide the following states:
* 1. The viewers' action persistence.
* 2. Access the viewers' action.
*/
public class ViewerStateManager {
// The single instance to provide the management.
private static volatile ViewerStateManager instance;
/**
* Get the single instance of the manager.
*
* @return The single instance of the viewer action manager.
*/
public static ViewerStateManager getInstance() {
if (instance == null) {
instance = new ViewerStateManager();
}
return instance;
}
// The map to store the viewers' states.
private Map<String, TreeViewerState> viewerStates;
/**
* Get the viewer action for the specified input id.
*
* @param inputId
* @return
*/
public TreeViewerState getViewerState(String inputId) {
return viewerStates.get(inputId);
}
/**
* Get the filter descriptor for the specified viewer and input.
*
* @param viewerId The viewer's id.
* @param input The input.
* @return The enabled filter descriptors.
*/
public FilterDescriptor[] getFilterDescriptors(String viewerId, Object input) {
if (input != null) {
TreeViewerExtension viewerExtension = new TreeViewerExtension(viewerId);
FilterDescriptor[] filterDescriptors = viewerExtension.parseFilters(input);
if (filterDescriptors != null) {
IViewerInput viewerInput = getViewerInput(input);
if(viewerInput != null) {
String inputId =viewerInput.getInputId();
inputId = viewerId + "." + inputId; //$NON-NLS-1$
TreeViewerState viewerState = getViewerState(inputId);
if (viewerState != null) {
viewerState.updateFilterDescriptor(filterDescriptors);
}
}
return filterDescriptors;
}
}
return new FilterDescriptor[0];
}
/***
* Get the viewer input from the input of the tree viewer.
* If the input is an instance of IViewerInput, then return
* the input. If the input can be adapted to a IViewerInput,
* then return the adapted object.
*
* @param input The input of the tree viewer.
* @return A viewer input or null.
*/
static IViewerInput getViewerInput(Object input) {
IViewerInput viewerInput = null;
if (input != null) {
if (input instanceof IViewerInput) {
viewerInput = (IViewerInput) input;
}
else {
if (input instanceof IAdaptable) {
viewerInput = (IViewerInput) ((IAdaptable) input).getAdapter(IViewerInput.class);
}
if (viewerInput == null) {
viewerInput = (IViewerInput) Platform.getAdapterManager().getAdapter(input, IViewerInput.class);
}
}
}
return viewerInput;
}
/**
* Put the viewer action with its input id into the map.
*
* @param inputId The id of the input.
* @param viewerState The viewer's action.
*/
public void putViewerState(String inputId, TreeViewerState viewerState) {
viewerStates.put(inputId, viewerState);
}
/**
* Load all the viewer states from an external storage. Called by the plugin's
* activator before they are used to configure the tree viewers.
*/
public void loadViewerStates() {
viewerStates = Collections.synchronizedMap(new HashMap<String, TreeViewerState>());
final File stateFile = getViewerStateFile();
if (stateFile.exists()) {
SafeRunner.run(new SafeRunnable() {
@Override
public void handleException(Throwable e) {
// Ignore exception
}
@Override
public void run() throws Exception {
Reader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(stateFile), "UTF-8")); //$NON-NLS-1$
XMLMemento root = XMLMemento.createReadRoot(reader);
loadViewerState(root);
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (IOException e) {
}
}
}
}
});
}
}
/**
* Load the viewer states from the memento root.
*
* @param root The memento's root.
*/
void loadViewerState(IMemento root) {
IMemento[] children = root.getChildren("viewerState"); //$NON-NLS-1$
if (children != null && children.length > 0) {
for (IMemento child : children) {
createViewerState(child);
}
}
}
/**
* Create a viewer action instance using the specified memento element.
*
* @param mViewerState The memento element.
*/
void createViewerState(IMemento mViewerState) {
String id = mViewerState.getString("id"); //$NON-NLS-1$
Assert.isNotNull(id);
TreeViewerState viewerState = new TreeViewerState();
viewerState.restoreState(mViewerState);
viewerStates.put(id, viewerState);
}
/**
* Get the viewer action files. The default location is a file named "viewerstates.xml"
* under the plugin's action cache. If it is not available, default it to the ".tcf"
* directory under the user's home.
*
* @return The viewer action file.
*/
private File getViewerStateFile() {
File location;
try {
location = UIPlugin.getDefault().getStateLocation().toFile();
}
catch (IllegalStateException e) {
// An RCP workspace-less environment (-data @none)
location = new File(System.getProperty("user.home"), ".tcf"); //$NON-NLS-1$ //$NON-NLS-2$
}
// Create the location if it not exist
if (!location.exists()) {
final File dir = location;
SafeRunner.run(new SafeRunnable(){
@Override
public void run() throws Exception {
if (!dir.mkdir()) {
throw new Exception(Messages.ViewerStateManager_MkdirFailed);
}
}});
}
location = new File(location, "viewerstates.xml"); //$NON-NLS-1$
return location;
}
/**
* Store the the viewer states. Called by the plugin's activator to
* save the action data.
*/
public void storeViewerStates() {
final File stateFile = getViewerStateFile();
final XMLMemento root = XMLMemento.createWriteRoot("viewerStates"); //$NON-NLS-1$
storeViewerStates(root);
SafeRunner.run(new SafeRunnable() {
@Override
public void handleException(Throwable e) {
// Ignore exception
}
@Override
public void run() throws Exception {
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(stateFile), "UTF-8")); //$NON-NLS-1$
root.save(writer);
}
finally {
if (writer != null) {
try {
writer.close();
}
catch (IOException e) {
}
}
}
}
});
}
/**
* Store the viewer's action to a memento element.
*
* @param root The memento element.
*/
void storeViewerStates(IMemento root) {
for (String id : viewerStates.keySet()) {
IMemento mViewerState = root.createChild("viewerState"); //$NON-NLS-1$
mViewerState.putString("id", id); //$NON-NLS-1$
TreeViewerState viewerState = viewerStates.get(id);
viewerState.saveState(mViewerState);
}
}
/**
* Create a viewer action instance using the column descriptors and the filter descriptors specified.
*
* @param columns The column descriptors.
* @param filters The filter descriptors.
* @return The tree viewer action instance.
*/
public static TreeViewerState createViewerState(ColumnDescriptor[] columns, FilterDescriptor[] filters) {
TreeViewerState viewerState = new TreeViewerState();
if (columns != null) {
for (ColumnDescriptor column : columns) {
viewerState.addColumn(column);
}
}
if (filters != null) {
for(FilterDescriptor filter : filters) {
viewerState.addFilter(filter);
}
}
return viewerState;
}
}