blob: 1ab89a5a136ba365559a14a6ae902a29e3ab9ac4 [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 Corporation - initial API and 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(""))) { //$NON-NLS-1$
/* 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;
}
}