blob: 7dbe37d9a4b8d0ee491e37c6b63380474492cd07 [file] [log] [blame]
/************************************************************************
Copyright (c) 2000, 2003 IBM Corporation and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Common Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v10.html
Contributors:
IBM - Initial implementation
************************************************************************/
package org.eclipse.ui.internal.registry;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.*;
import org.eclipse.ui.internal.*;
import org.eclipse.ui.plugin.AbstractUIPlugin;
/**
* Perspective registry.
*/
public class PerspectiveRegistry implements IPerspectiveRegistry {
private ArrayList children = new ArrayList(10);
private String defaultPerspID;
private static final String EXT = "_persp.xml";//$NON-NLS-1$
private static final String ID_DEF_PERSP = "PerspectiveRegistry.DEFAULT_PERSP";//$NON-NLS-1$
private static final String PERSP = "_persp"; //$NON-NLS-1$
private static final char SPACE_DELIMITER = ' '; //$NON-NLS-1$
//keep track of the perspectives the user has selected to remove or revert
private ArrayList perspToRemove = new ArrayList(5);
/**
* Construct a new registry.
*
* @param rootFolder is the root folder for perspective files.
*/
public PerspectiveRegistry() {
super();
IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
store.addPropertyChangeListener(new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
/* To ensure the that no custom perspective definitions are deleted
* when preferences are imported, merge old and new values */
if (event.getProperty().endsWith(PERSP)) {
/* A Perspective is being changed, merge */
mergePerspectives(event);
} else if (event.getProperty().equals(IPreferenceConstants.PERSPECTIVES)) {
/* The list of perpsectives is being changed, merge */
updatePreferenceList((IPreferenceStore)event.getSource());
}
}
private void mergePerspectives(PropertyChangeEvent event) {
IPreferenceStore store = (IPreferenceStore)event.getSource();
if (event.getNewValue() == null) {
/* Perpsective is being removed; if the user has deleted or reverted
* a custom perspective, let the change pass through.
* Otherwise, restore the custom perspective entry */
// Find the matching descriptor in the registry
IPerspectiveDescriptor [] perspectiveList = getPerspectives();
for (int i = 0; i < perspectiveList.length; i++) {
String id = perspectiveList[i].getId();
if (event.getProperty().startsWith(id)) { //found descriptor
//see if the perspective has been flagged for reverting or deleting
if ( ! perspToRemove.contains(id)) { //restore
store.setValue(id + PERSP, (String)event.getOldValue());
} else { //remove element from the list
perspToRemove.remove(id);
}
}
}
} else if ((event.getOldValue() == null || event.getOldValue().equals(""))) {
/* New perspective is being added, update the perspectiveRegistry to
* contain the new custom perspective */
String id = event.getProperty().substring(0, event.getProperty().lastIndexOf(PERSP));
if (findPerspectiveWithId(id) == null) {
//perspective does not already exist in registry, add it
PerspectiveDescriptor desc = new PerspectiveDescriptor(null, null, null);
StringReader reader = new StringReader((String)event.getNewValue());
try {
XMLMemento memento = XMLMemento.createReadRoot(reader);
desc.restoreState(memento);
children.add(desc);
} catch (WorkbenchException e) {
unableToLoadPerspective(e.getStatus());
}
}
}
/* If necessary, add to the list of perspectives */
updatePreferenceList(store);
}
/* Update the list of perspectives from the registry. This will be called
* for each perspective during an import preferences, but is necessary
* to ensure the perspectives list stays consistent with the registry */
private void updatePreferenceList(IPreferenceStore store) {
IPerspectiveDescriptor [] perspectiveList = getPerspectives();
StringBuffer perspBuffer = new StringBuffer();
for (int i = 0; i < perspectiveList.length; i++) {
PerspectiveDescriptor desc = (PerspectiveDescriptor) perspectiveList[i];
if (hasCustomDefinition(desc)) {
perspBuffer.append(desc.getId()).append(SPACE_DELIMITER);
}
}
String newList = perspBuffer.toString().trim();
store.setValue(IPreferenceConstants.PERSPECTIVES, newList);
}
});
}
/**
* Adds a perspective. This is typically used by the reader.
*/
public void addPerspective(PerspectiveDescriptor desc) {
children.add(desc);
}
/**
* Create a new perspective.
* Return null if the creation failed.
*/
public PerspectiveDescriptor createPerspective(String label,PerspectiveDescriptor originalDescriptor) {
// Sanity check to avoid duplicate labels.
if (!validateLabel(label))
return null;
// Calculate ID.
String id = label.replace(' ', '_');
id = id.trim();
// Create descriptor.
PerspectiveDescriptor desc = new PerspectiveDescriptor(id, label,originalDescriptor);
children.add(desc);
return desc;
}
/**
* Reverts a list of perspectives back to the plugin definition
* @param perspToRevert
*/
public void revertPerspectives(ArrayList perspToRevert) {
//indicate that the user is removing these perspectives
for (int i = 0; i < perspToRevert.size(); i++) {
PerspectiveDescriptor desc = (PerspectiveDescriptor) perspToRevert.get(i);
perspToRemove.add(desc.getId());
desc.revertToPredefined();
}
}
/**
* Deletes a list of perspectives
* @param perspToDelete
*/
public void deletePerspectives(ArrayList perspToDelete) {
for (int i = 0; i < perspToDelete.size(); i++)
deletePerspective((IPerspectiveDescriptor) perspToDelete.get(i));
}
/**
* Delete a perspective.
* Has no effect if the perspective is defined in an extension.
*/
public void deletePerspective(IPerspectiveDescriptor in) {
PerspectiveDescriptor desc = (PerspectiveDescriptor)in;
if (!desc.isPredefined()) {
//indicate that the user is removing these perspectives
perspToRemove.add(desc.getId());
children.remove(desc);
desc.deleteCustomDefinition();
verifyDefaultPerspective();
}
}
/**
* Removes the custom definition of a perspective from the preference sotre
* @param perspectiveDescriptor
*/
/* package */ void deleteCustomDefinition(PerspectiveDescriptor desc) {
//remove the entry from the preference store.
IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
/* To delete the perspective definition from the preference store, use the
* setToDefault method. Since no default is defined, this will remove the
* entry */
store.setToDefault(desc.getId() + PERSP);
}
/**
* Method hasCustomDefinition.
* @param perspectiveDescriptor
*/
/* package */ boolean hasCustomDefinition(PerspectiveDescriptor desc) {
IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
return store.contains(desc.getId() + PERSP);
}
/**
* @see IPerspectiveRegistry
*/
public IPerspectiveDescriptor findPerspectiveWithId(String id) {
Iterator enum = children.iterator();
while (enum.hasNext()) {
IPerspectiveDescriptor desc = (IPerspectiveDescriptor)enum.next();
if (desc.getId().equals(id))
return desc;
}
return null;
}
/**
* @see IPerspectiveRegistry
*/
public IPerspectiveDescriptor findPerspectiveWithLabel(String label) {
Iterator enum = children.iterator();
while (enum.hasNext()) {
IPerspectiveDescriptor desc = (IPerspectiveDescriptor)enum.next();
if (desc.getLabel().equals(label))
return desc;
}
return null;
}
/**
* Returns the id of the default perspective for the workbench. This identifies one
* perspective extension within the workbench's perspective registry.
*
* @return the default perspective id; will never be <code>null</code>
*/
public String getDefaultPerspective() {
return defaultPerspID;
}
/**
* @see IPerspectiveRegistry
*/
public IPerspectiveDescriptor[] getPerspectives() {
int nSize = children.size();
IPerspectiveDescriptor [] retArray = new IPerspectiveDescriptor[nSize];
for (int nX = 0; nX < nSize; nX ++) {
retArray[nX] = (IPerspectiveDescriptor)children.get(nX);
}
return retArray;
}
/**
* Loads the registry.
*/
public void load() {
// Load the registries.
loadPredefined();
loadCustom();
// Get default perspective.
// Get it from the R1.0 dialog settings first. Fixes bug 17039
IDialogSettings dialogSettings = WorkbenchPlugin.getDefault().getDialogSettings();
String str = dialogSettings.get(ID_DEF_PERSP);
if (str != null && str.length() > 0) {
setDefaultPerspective(str);
dialogSettings.put(ID_DEF_PERSP, ""); //$NON-NLS-1$
} else {
AbstractUIPlugin plugin = (AbstractUIPlugin) Platform.getPlugin(PlatformUI.PLUGIN_ID);
defaultPerspID =
plugin.getPreferenceStore().getString(IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID);
}
verifyDefaultPerspective();
}
/**
* Read children from the file system.
*/
private void loadCustom() {
Reader reader = null;
/* Get the entries from the Preference store */
IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
/* Get the space-delimited list of custom perspective ids */
String customPerspectives = store.getString(IPreferenceConstants.PERSPECTIVES);
String [] perspectivesList = StringConverter.asArray(customPerspectives);
for (int i = 0; i < perspectivesList.length; i++) {
try {
String xmlString = store.getString(perspectivesList[i] + PERSP);
if(xmlString != null && xmlString.length() != 0)
reader = new StringReader(xmlString);
// Restore the layout state.
XMLMemento memento = XMLMemento.createReadRoot(reader);
PerspectiveDescriptor newPersp = new PerspectiveDescriptor(null, null, null);
newPersp.restoreState(memento);
String id = newPersp.getId();
IPerspectiveDescriptor oldPersp = findPerspectiveWithId(id);
if (oldPersp == null)
children.add(newPersp);
reader.close();
} catch (IOException e) {
unableToLoadPerspective(null);
} catch (WorkbenchException e) {
unableToLoadPerspective(e.getStatus());
}
}
/* Get the entries from files, if any */
IPath path = WorkbenchPlugin.getDefault().getStateLocation();
File folder = path.toFile();
if (folder.isDirectory()) {
File [] fileList = folder.listFiles();
int nSize = fileList.length;
for (int nX = 0; nX < nSize; nX ++) {
File file = fileList[nX];
if (file.getName().endsWith(EXT)) {
//get the memento
InputStream stream = null;
try {
stream = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(stream, "utf-8")); //$NON-NLS-1$
// Restore the layout state.
XMLMemento memento = XMLMemento.createReadRoot(reader);
PerspectiveDescriptor newPersp = new PerspectiveDescriptor(null, null, null);
newPersp.restoreState(memento);
IPerspectiveDescriptor oldPersp = findPerspectiveWithId(newPersp.getId());
if (oldPersp == null)
children.add(newPersp);
//save to the preference store
saveCustomPersp(newPersp, memento);
//delete the file
file.delete();
reader.close();
stream.close();
} catch (IOException e) {
unableToLoadPerspective(null);
} catch (WorkbenchException e) {
unableToLoadPerspective(e.getStatus());
}
}
}
}
}
private void unableToLoadPerspective(IStatus status) {
String title = WorkbenchMessages.getString("Perspective.problemLoadingTitle"); //$NON-NLS-1$
String msg = WorkbenchMessages.getString("Perspective.errorLoadingState"); //$NON-NLS-1$
if(status == null) {
MessageDialog.openError((Shell)null,title,msg);
} else {
ErrorDialog.openError((Shell)null,title,msg,status);
}
}
/**
* Saves a custom perspective definition to the preference store.
* @param desc
*/
public void saveCustomPersp(PerspectiveDescriptor realDesc, XMLMemento memento) throws IOException {
IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
// Save it to the preference store.
Writer writer = new StringWriter();;
memento.save(writer);
writer.close();
store.setValue(realDesc.getId() + PERSP,writer.toString());
}
/**
* Gets the Custom perspective definition from the preference store.
* @param string
* @return IMemento
*/
public IMemento getCustomPersp(String id) throws WorkbenchException, IOException {
Reader reader = null;
IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
String xmlString = store.getString(id + PERSP);
if(xmlString != null && xmlString.length() != 0) { //defined in store
reader = new StringReader(xmlString);
}
XMLMemento memento = XMLMemento.createReadRoot(reader);
reader.close();
return memento;
}
/**
* Read children from the plugin registry.
*/
private void loadPredefined() {
PerspectiveRegistryReader reader = new PerspectiveRegistryReader();
reader.readPerspectives(Platform.getPluginRegistry(), this);
}
/**
* Sets the default perspective for the workbench to the given perspective id.
* The id must correspond to one perspective extension within the workbench's
* perspective registry.
*
* @param id a perspective id; must not be <code>null</code>
*/
public void setDefaultPerspective(String id) {
IPerspectiveDescriptor desc = findPerspectiveWithId(id);
if (desc != null) {
defaultPerspID = id;
AbstractUIPlugin uiPlugin =
(AbstractUIPlugin) Platform.getPlugin(PlatformUI.PLUGIN_ID);
uiPlugin.getPreferenceStore().
setValue(IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID, id);
}
}
/**
* Return true if a label is valid and unused.
*/
public boolean validateLabel(String label) {
label = label.trim();
if (label.length() <= 0)
return false;
return true;
}
/**
* Verifies the id of the default perspective. If the
* default perspective is invalid use the workbench default.
*/
private void verifyDefaultPerspective() {
// Step 1: Try current defPerspId value.
IPerspectiveDescriptor desc = null;
if (defaultPerspID != null)
desc = findPerspectiveWithId(defaultPerspID);
if (desc != null)
return;
// Step 2. Read default value.
AbstractUIPlugin uiPlugin =
(AbstractUIPlugin) Platform.getPlugin(PlatformUI.PLUGIN_ID);
defaultPerspID =
uiPlugin.getPreferenceStore().getDefaultString(IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID);
if (defaultPerspID != null)
desc = findPerspectiveWithId(defaultPerspID);
if (desc != null)
return;
// Step 3. Use internal workbench default.
defaultPerspID = IWorkbenchConstants.DEFAULT_LAYOUT_ID;
}
}