Replace the rename key code to use the Eclipse refactoring framework
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java
index 9ddfeeb..d88ddc6 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java
@@ -14,27 +14,72 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
+import java.util.StringTokenizer;
import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.MessagesBundleGroupAdapter;
import org.eclipse.babel.core.message.tree.visitor.IKeyTreeVisitor;
/**
* Hierarchical representation of all keys making up a
* {@link MessagesBundleGroup}.
-
+ *
+ * Key tree model, using a delimiter to separate key sections
+ * into nodes. For instance, a dot (.) delimiter on the following key...<p>
+ * <code>person.address.street</code><P>
+ * ... will result in the following node hierarchy:<p>
+ * <pre>
+ * person
+ * address
+ * street
+ * </pre>
+ *
* @author Pascal Essiembre
*/
-public abstract class AbstractKeyTreeModel {
+public class AbstractKeyTreeModel {
private List<IKeyTreeModelListener> listeners = new ArrayList<IKeyTreeModelListener>();
private Comparator<KeyTreeNode> comparator;
+ private KeyTreeNode rootNode = new KeyTreeNode(null, null, null);
+
+ private String delimiter;
+ private MessagesBundleGroup messagesBundleGroup;
+
protected static final KeyTreeNode[] EMPTY_NODES = new KeyTreeNode[]{};
/**
+ * Defaults to ".".
+ */
+ public AbstractKeyTreeModel(MessagesBundleGroup messagesBundleGroup) {
+ this(messagesBundleGroup, "."); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructor.
+ * @param messagesBundleGroup {@link MessagesBundleGroup} instance
+ * @param delimiter key section delimiter
+ */
+ public AbstractKeyTreeModel(
+ MessagesBundleGroup messagesBundleGroup, String delimiter) {
+ super();
+ this.messagesBundleGroup = messagesBundleGroup;
+ this.delimiter = delimiter;
+ createTree();
+
+ messagesBundleGroup.addMessagesBundleGroupListener(
+ new MessagesBundleGroupAdapter() {
+ public void keyAdded(String key) {
+ createTreeNodes(key);
+ }
+ public void keyRemoved(String key) {
+ removeTreeNodes(key);
+ }
+ });
+ }
+
+ /**
* Adds a key tree model listener.
* @param listener key tree model listener
*/
@@ -76,14 +121,9 @@
* @param parentNode root of a branch
* @return all nodes on a branch
*/
+ // TODO inline and remove this method.
public KeyTreeNode[] getBranch(KeyTreeNode parentNode) {
- Set<KeyTreeNode> childNodes = new TreeSet<KeyTreeNode>();
- childNodes.add(parentNode);
- for (KeyTreeNode childNode : getChildren(parentNode)) {
- childNodes.addAll(
- Arrays.asList(getBranch(childNode)));
- }
- return childNodes.toArray(EMPTY_NODES);
+ return parentNode.getBranch().toArray(new KeyTreeNode[]{});
}
/**
@@ -103,7 +143,18 @@
}
}
- public abstract KeyTreeNode[] getChildren(KeyTreeNode node);
+ /**
+ * Gets the child nodes of a given key tree node.
+ * @param node the node from which to get children
+ * @return child nodes
+ */
+ public KeyTreeNode[] getChildren(KeyTreeNode node) {
+ KeyTreeNode[] nodes = node.getChildren();
+ if (getComparator() != null) {
+ Arrays.sort(nodes, getComparator());
+ }
+ return nodes;
+ }
/**
* Gets the comparator.
@@ -143,6 +194,104 @@
return false;
}
+ /**
+ * Gets the delimiter.
+ * @return delimiter
+ */
+ public String getDelimiter() {
+ return delimiter;
+ }
+ /**
+ * Sets the delimiter.
+ * @param delimiter delimiter
+ */
+ public void setDelimiter(String delimiter) {
+ this.delimiter = delimiter;
+ }
+
+ /**
+ * Gets the key tree root nodes.
+ * @return key tree root nodes
+ */
+ public KeyTreeNode[] getRootNodes() {
+ return getChildren(rootNode);
+ }
+
+ public KeyTreeNode getRootNode() {
+ return rootNode;
+ }
+
+ /**
+ * Gets the parent node of the given node.
+ * @param node node from which to get parent
+ * @return parent node
+ */
+ public KeyTreeNode getParent(KeyTreeNode node) {
+ return node.getParent();
+ }
+
+ /**
+ * Gets the messages bundle group that this key tree represents.
+ * @return messages bundle group
+ */
+ public MessagesBundleGroup getMessagesBundleGroup() {
+ //TODO consider moving this method (and part of constructor) to super
+ return messagesBundleGroup;
+ }
+
+ private void createTree() {
+ rootNode = new KeyTreeNode(null, null, null);
+ String[] keys = messagesBundleGroup.getMessageKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ createTreeNodes(key);
+ }
+ }
+
+ private void createTreeNodes(String bundleKey) {
+ StringTokenizer tokens = new StringTokenizer(bundleKey, delimiter);
+ KeyTreeNode node = rootNode;
+ String bundleKeyPart = ""; //$NON-NLS-1$
+ while (tokens.hasMoreTokens()) {
+ String name = tokens.nextToken();
+ bundleKeyPart += name;
+ KeyTreeNode child = node.getChild(name);
+ if (child == null) {
+ child = new KeyTreeNode(node, name, bundleKeyPart);
+ fireNodeAdded(child);
+ }
+ bundleKeyPart += delimiter;
+ node = child;
+ }
+ node.setUsedAsKey();
+ }
+ private void removeTreeNodes(String bundleKey) {
+ if (bundleKey == null) {
+ return;
+ }
+ StringTokenizer tokens = new StringTokenizer(bundleKey, delimiter);
+ KeyTreeNode node = rootNode;
+ while (tokens.hasMoreTokens()) {
+ String name = tokens.nextToken();
+ node = node.getChild(name);
+ if (node == null) {
+ System.err.println(
+ "No RegEx node matching bundleKey to remove"); //$NON-NLS-1$
+ return;
+ }
+ }
+ KeyTreeNode parentNode = node.getParent();
+ parentNode.removeChild(node);
+ fireNodeRemoved(node);
+ while (parentNode != rootNode) {
+ if (!parentNode.hasChildren() && !messagesBundleGroup.isMessageKey(
+ parentNode.getMessageKey())) {
+ parentNode.getParent().removeChild(parentNode);
+ fireNodeRemoved(parentNode);
+ }
+ parentNode = parentNode.getParent();
+ }
+ }
public interface IKeyTreeNodeLeafFilter {
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/DefaultKeyTreeModel.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/DefaultKeyTreeModel.java
deleted file mode 100644
index 38f3919..0000000
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/DefaultKeyTreeModel.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 Pascal Essiembre.
- * 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:
- * Pascal Essiembre - initial API and implementation
- ******************************************************************************/
-package org.eclipse.babel.core.message.tree;
-
-import java.util.Arrays;
-import java.util.StringTokenizer;
-
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.MessagesBundleGroupAdapter;
-
-
-/**
- * Default key tree model, using a delimiter to separate key sections
- * into nodes. For instance, a dot (.) delimiter on the following key...<p>
- * <code>person.address.street</code><P>
- * ... will result in the following node hierarchy:<p>
- * <pre>
- * person
- * address
- * street
- * </p>
- * @author Pascal Essiembre
- */
-public class DefaultKeyTreeModel extends AbstractKeyTreeModel {
-
- private KeyTreeNode rootNode = new KeyTreeNode(null, null, null);
-
- private String delimiter;
- private MessagesBundleGroup messagesBundleGroup;
-
- /**
- * Defaults to ".".
- */
- public DefaultKeyTreeModel(MessagesBundleGroup messagesBundleGroup) {
- this(messagesBundleGroup, "."); //$NON-NLS-1$
- }
- /**
- * Constructor.
- * @param messagesBundleGroup {@link MessagesBundleGroup} instance
- * @param delimiter key section delimiter
- */
- public DefaultKeyTreeModel(
- MessagesBundleGroup messagesBundleGroup, String delimiter) {
- super();
- this.messagesBundleGroup = messagesBundleGroup;
- this.delimiter = delimiter;
- createTree();
-
- messagesBundleGroup.addMessagesBundleGroupListener(
- new MessagesBundleGroupAdapter() {
- public void keyAdded(String key) {
- createTreeNodes(key);
- }
- public void keyRemoved(String key) {
- removeTreeNodes(key);
- }
- });
- }
-
- /**
- * Gets the delimiter.
- * @return delimiter
- */
- public String getDelimiter() {
- return delimiter;
- }
- /**
- * Sets the delimiter.
- * @param delimiter delimiter
- */
- public void setDelimiter(String delimiter) {
- this.delimiter = delimiter;
- }
-
- /**
- * Gets the key tree root nodes.
- * @return key tree root nodes
- */
- public KeyTreeNode[] getRootNodes() {
- return getChildren(rootNode);
- }
-
- public KeyTreeNode getRootNode() {
- return rootNode;
- }
-
- /**
- * Gets the child nodes of a given key tree node.
- * @param node the node from which to get children
- * @return child nodes
- */
- public KeyTreeNode[] getChildren(KeyTreeNode node) {
- KeyTreeNode[] nodes = node.getChildren();
- if (getComparator() != null) {
- Arrays.sort(nodes, getComparator());
- }
- return nodes;
- }
-
- /**
- * Gets the parent node of the given node.
- * @param node node from which to get parent
- * @return parent node
- */
- public KeyTreeNode getParent(KeyTreeNode node) {
- return node.getParent();
- }
-
- /**
- * Gets the messages bundle group that this key tree represents.
- * @return messages bundle group
- */
- public MessagesBundleGroup getMessagesBundleGroup() {
- //TODO consider moving this method (and part of constructor) to super
- return messagesBundleGroup;
- }
-
- private void createTree() {
- rootNode = new KeyTreeNode(null, null, null);
- String[] keys = messagesBundleGroup.getMessageKeys();
- for (int i = 0; i < keys.length; i++) {
- String key = keys[i];
- createTreeNodes(key);
- }
- }
-
- private void createTreeNodes(String bundleKey) {
- if (bundleKey == null) {
- return;
- }
- StringTokenizer tokens = new StringTokenizer(bundleKey, delimiter);
- KeyTreeNode node = rootNode;
- String bundleKeyPart = ""; //$NON-NLS-1$
- while (tokens.hasMoreTokens()) {
- String name = tokens.nextToken();
- bundleKeyPart += name;
- KeyTreeNode child = node.getChild(name);
- if (child == null) {
- child = new KeyTreeNode(node, name, bundleKeyPart);
- fireNodeAdded(child);
- }
- bundleKeyPart += delimiter;
- node = child;
- }
- }
- private void removeTreeNodes(String bundleKey) {
- if (bundleKey == null) {
- return;
- }
- StringTokenizer tokens = new StringTokenizer(bundleKey, delimiter);
- KeyTreeNode node = rootNode;
- while (tokens.hasMoreTokens()) {
- String name = tokens.nextToken();
- node = node.getChild(name);
- if (node == null) {
- System.err.println(
- "No RegEx node matching bundleKey to remove"); //$NON-NLS-1$
- return;
- }
- }
- KeyTreeNode parentNode = node.getParent();
- parentNode.removeChild(node);
- fireNodeRemoved(node);
- while (parentNode != rootNode) {
- if (!parentNode.hasChildren() && !messagesBundleGroup.isMessageKey(
- parentNode.getMessageKey())) {
- parentNode.getParent().removeChild(parentNode);
- fireNodeRemoved(parentNode);
- }
- parentNode = parentNode.getParent();
- }
- }
-}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java
index b797b4f..0c469db 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java
@@ -48,6 +48,8 @@
private String messageKey;
private final Map<String, KeyTreeNode> children = new TreeMap<String, KeyTreeNode>();
+
+ private boolean usedAsKey = false;
/**
* Constructor.
@@ -105,13 +107,13 @@
return nodes.toArray(EMPTY_KEY_TREE_NODES);
}
- /*default*/ KeyTreeNode[] getChildren() {
+ public KeyTreeNode[] getChildren() {
return children.values().toArray(EMPTY_KEY_TREE_NODES);
}
/*default*/ boolean hasChildren() {
return !children.isEmpty();
}
- /*default*/ KeyTreeNode getChild(String childName) {
+ public KeyTreeNode getChild(String childName) {
return children.get(childName);
}
@@ -126,6 +128,8 @@
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(KeyTreeNode node) {
+ // TODO this is wrong. For example, menu.label and textbox.label are indicated as equal,
+ // which means they overwrite each other in the tree set!!!
if (parent == null && node.parent != null) {
return -1;
}
@@ -164,6 +168,16 @@
//TODO remove parent on child node?
}
+ // TODO: remove this, or simplify it using method getDescendants
+ public Collection<KeyTreeNode> getBranch() {
+ Collection<KeyTreeNode> childNodes = new ArrayList<KeyTreeNode>();
+ childNodes.add(this);
+ for (KeyTreeNode childNode : this.getChildren()) {
+ childNodes.addAll(childNode.getBranch());
+ }
+ return childNodes;
+ }
+
public Collection<KeyTreeNode> getDescendants() {
Collection<KeyTreeNode> descendants = new ArrayList<KeyTreeNode>();
for (KeyTreeNode child : children.values()) {
@@ -172,5 +186,26 @@
}
return descendants;
}
+
+ /**
+ * Marks this node as representing an actual key.
+ * <P>
+ * For example, if the bundle contains two keys:
+ * <UL>
+ * <LI>foo.bar</LI>
+ * <LI>foo.bar.tooltip</LI>
+ * </UL>
+ * This will create three nodes, foo, which has a child
+ * node called bar, which has a child node called tooltip.
+ * However foo is not an actual key but is only a parent node.
+ * foo.bar is an actual key even though it is also a parent node.
+ */
+ public void setUsedAsKey() {
+ usedAsKey = true;
+ }
+
+ public boolean isUsedAsKey() {
+ return usedAsKey;
+ }
}
diff --git a/org.eclipse.babel.editor/META-INF/MANIFEST.MF b/org.eclipse.babel.editor/META-INF/MANIFEST.MF
index 1df0acd..25870b8 100644
--- a/org.eclipse.babel.editor/META-INF/MANIFEST.MF
+++ b/org.eclipse.babel.editor/META-INF/MANIFEST.MF
@@ -14,6 +14,8 @@
org.eclipse.ui.forms;bundle-version="3.2.0",
org.eclipse.core.resources;bundle-version="3.2.0",
org.eclipse.jdt.core;bundle-version="3.2.0",
+ org.eclipse.ltk.core.refactoring,
+ org.eclipse.ltk.ui.refactoring,
org.eclipse.pde.core;bundle-version="3.2.0",
org.junit;resolution:=optional,
org.eclipse.babel.core
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java
index 62ca038..0c30b8b 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java
@@ -21,7 +21,6 @@
import org.eclipse.babel.core.message.MessagesBundleGroup;
import org.eclipse.babel.core.message.resource.IMessagesResource;
import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.core.message.tree.DefaultKeyTreeModel;
import org.eclipse.babel.editor.builder.ToggleNatureAction;
import org.eclipse.babel.editor.bundle.MessagesBundleGroupFactory;
import org.eclipse.babel.editor.i18n.I18NPage;
@@ -121,7 +120,7 @@
closeIfAreadyOpen(site, file);
super.init(site, editorInput);
//TODO figure out model to use based on preferences
- keyTreeModel = new DefaultKeyTreeModel(messagesBundleGroup);
+ keyTreeModel = new AbstractKeyTreeModel(messagesBundleGroup);
// markerManager = new RBEMarkerManager(this);
} else {
throw new PartInitException(
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java
index 88ef9e1..e677ec8 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java
@@ -27,6 +27,7 @@
import org.eclipse.babel.editor.resource.validator.MessagesBundleGroupValidator;
import org.eclipse.babel.editor.resource.validator.ValidationFailureEvent;
import org.eclipse.babel.editor.util.UIUtils;
+import org.eclipse.swt.widgets.Display;
/**
@@ -66,7 +67,11 @@
public void messagesBundleChanged(
MessagesBundle messagesBundle,
PropertyChangeEvent changeEvent) {
- resetMarkers();
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run() {
+ resetMarkers();
+ }
+ });
}
public void propertyChange(PropertyChangeEvent evt) {
resetMarkers();
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java
index 7674643..ef9d134 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java
@@ -54,27 +54,23 @@
import org.osgi.framework.Bundle;
/**
- * This strategy is used when a resource bundle that belongs to Plugin-Fragment
+ * This strategy is used when a resource bundle that belongs to a plug-in fragment
* project is loaded.
* <p>
- * This class loads resource bundles following the default strategy.
- * If no root locale resource is found, it tries to locate that resource
- * inside the host-plugin of the fragment. The host plugin is searched inside
- * the workspace
- * first and if not found inside the eclipse-platform being run.
- * </p>
+ * This class loads resource bundles following the default strategy. If no root
+ * locale resource is found, it tries to locate that resource inside the
+ * host plug-in of the fragment. The host plug-in is searched inside the workspace
+ * first and if not found inside the Eclipse platform being run.
* <p>
- * This is useful for the developement of i18n packages for eclipse plugin:
- * The best practice is to define the root locale messages inside the plugin
- * itself and to define the other locales in a fragment that host that plugin.
- * <br/>Thanks to this strategy the root locale can be used by the user when
- * he edits
+ * This is useful for the development of i18n packages for eclipse plug-ins: The
+ * best practice is to define the root locale messages inside the plug-in itself
+ * and to define the other locales in a fragment that host that plug-in. Thanks
+ * to this strategy the root locale can be used by the user when the user edits
* the messages defined in the fragment alone.
- * <p>
- * See Bug #214521.
- * </p>
+ *
* @author Pascal Essiembre
* @author Hugues Malphettes
+ * @see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=214521">Bug 214521 - in the resource bundle editor take into account the resources of the "Host-Plugin" when opened bundle is in a plugin-fragment</a>
*/
public class NLFragmentBundleGroupStrategy extends NLPluginBundleGroupStrategy {
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyArguments.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyArguments.java
new file mode 100644
index 0000000..f22ce92
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyArguments.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nigel Westbury
+ * 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:
+ * Nigel Westbury - initial implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.refactoring;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
+
+/**
+ * This class contains the data that a processor provides to its rename resource
+ * bundle key participants.
+ */
+public class RenameKeyArguments extends RefactoringArguments {
+
+ private String fNewName;
+
+ private boolean fRenameChildKeys;
+
+ private boolean fUpdateReferences;
+
+ /**
+ * Creates new rename arguments.
+ *
+ * @param newName
+ * the new name of the element to be renamed
+ * @param renameChildKeys
+ * <code>true</code> if child keys are to be renamed;
+ * <code>false</code> otherwise
+ * @param updateReferences
+ * <code>true</code> if reference updating is requested;
+ * <code>false</code> otherwise
+ */
+ public RenameKeyArguments(String newName, boolean renameChildKeys, boolean updateReferences) {
+ Assert.isNotNull(newName);
+ fNewName= newName;
+ fRenameChildKeys = renameChildKeys;
+ fUpdateReferences= updateReferences;
+ }
+
+ /**
+ * Returns the new element name.
+ *
+ * @return the new element name
+ */
+ public String getNewName() {
+ return fNewName;
+ }
+
+ /**
+ * Returns whether child keys are to be renamed or not.
+ *
+ * @return returns <code>true</code> if child keys are to be renamed;
+ * <code>false</code> otherwise
+ */
+ public boolean getRenameChildKeys() {
+ return fRenameChildKeys;
+ }
+
+ /**
+ * Returns whether reference updating is requested or not.
+ *
+ * @return returns <code>true</code> if reference updating is requested;
+ * <code>false</code> otherwise
+ */
+ public boolean getUpdateReferences() {
+ return fUpdateReferences;
+ }
+
+ public String toString() {
+ return "rename to " + fNewName //$NON-NLS-1$
+ + (fRenameChildKeys ? " (rename child keys)" : " (don't rename child keys)") //$NON-NLS-1$//$NON-NLS-2$
+ + (fUpdateReferences ? " (update references)" : " (don't update references)"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java
new file mode 100644
index 0000000..961caae
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nigel Westbury
+ * 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:
+ * Nigel Westbury - initial implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.refactoring;
+
+import java.text.MessageFormat;
+import java.util.Collection;
+
+import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+/**
+ * {@link Change} that renames a resource bundle key.
+ */
+public class RenameKeyChange extends Change {
+
+ private final MessagesBundleGroup fMessagesBundleGroup;
+
+ private final String fNewName;
+
+ private final boolean fRenameChildKeys;
+
+ private final KeyTreeNode fKeyTreeNode;
+
+ private ChangeDescriptor fDescriptor;
+
+ /**
+ * Creates the change.
+ *
+ * @param keyTreeNode the node in the model to rename
+ * @param newName the new name. Must not be empty
+ * @param renameChildKeys true if child keys are also to be renamed, false if just this one key is to be renamed
+ */
+ protected RenameKeyChange(MessagesBundleGroup messageBundleGroup, KeyTreeNode keyTreeNode, String newName, boolean renameChildKeys) {
+ if (keyTreeNode == null || newName == null || newName.length() == 0) {
+ throw new IllegalArgumentException();
+ }
+
+ fMessagesBundleGroup = messageBundleGroup;
+ fKeyTreeNode= keyTreeNode;
+ fNewName= newName;
+ fRenameChildKeys = renameChildKeys;
+ fDescriptor= null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.Change#getDescriptor()
+ */
+ public ChangeDescriptor getDescriptor() {
+ return fDescriptor;
+ }
+
+ /**
+ * Sets the change descriptor to be returned by {@link Change#getDescriptor()}.
+ *
+ * @param descriptor the change descriptor
+ */
+ public void setDescriptor(ChangeDescriptor descriptor) {
+ fDescriptor= descriptor;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.Change#getName()
+ */
+ public String getName() {
+ return MessageFormat.format("Rename {0} to {1}", new Object [] { fKeyTreeNode.getMessageKey(), fNewName});
+ }
+
+ /**
+ * Returns the new name.
+ *
+ * @return return the new name
+ */
+ public String getNewName() {
+ return fNewName;
+ }
+
+ /**
+ * This implementation of {@link Change#isValid(IProgressMonitor)} tests the modified resource using the validation method
+ * specified by {@link #setValidationMethod(int)}.
+ */
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+ pm.beginTask("", 2); //$NON-NLS-1$
+ try {
+ RefactoringStatus result = new RefactoringStatus();
+ return result;
+ } finally {
+ pm.done();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.Change#initializeValidationData(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void initializeValidationData(IProgressMonitor pm) {
+ }
+
+ public Object getModifiedElement() {
+ return "what is this for?";
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.Change#perform(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ try {
+ pm.beginTask("Rename resource bundle key", 1);
+
+ // Find the root - we will need this later
+ KeyTreeNode root = fKeyTreeNode.getParent();
+ while (root.getName() != null) {
+ root = root.getParent();
+ }
+
+ if (fRenameChildKeys) {
+ String key = fKeyTreeNode.getMessageKey();
+ String keyPrefix = fKeyTreeNode.getMessageKey() + ".";
+ Collection<KeyTreeNode> branchNodes = fKeyTreeNode.getBranch();
+ for (KeyTreeNode branchNode : branchNodes) {
+ String oldKey = branchNode.getMessageKey();
+ if (oldKey.equals(key) || oldKey.startsWith(keyPrefix)) {
+ String newKey = fNewName + oldKey.substring(key.length());
+ fMessagesBundleGroup.renameMessageKeys(oldKey, newKey);
+ }
+ }
+ } else {
+ fMessagesBundleGroup.renameMessageKeys(fKeyTreeNode.getMessageKey(), fNewName);
+ }
+
+ String oldName= fKeyTreeNode.getMessageKey();
+
+ // Find the node that was created with the new name
+ String segments [] = fNewName.split("\\.");
+ KeyTreeNode renamedKey = root;
+ for (String segment : segments) {
+ renamedKey = renamedKey.getChild(segment);
+ }
+
+ assert(renamedKey != null);
+ return new RenameKeyChange(fMessagesBundleGroup, renamedKey, oldName, fRenameChildKeys);
+ } finally {
+ pm.done();
+ }
+ }
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java
new file mode 100644
index 0000000..9251999
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nigel Westbury
+ * 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:
+ * Nigel Westbury - initial implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.refactoring;
+
+import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContribution;
+import org.eclipse.ltk.core.refactoring.RefactoringCore;
+import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
+
+/**
+ * Refactoring descriptor for the rename resource bundle key refactoring.
+ * <p>
+ * An instance of this refactoring descriptor may be obtained by calling
+ * {@link RefactoringContribution#createDescriptor()} on a refactoring
+ * contribution requested by invoking
+ * {@link RefactoringCore#getRefactoringContribution(String)} with the
+ * refactoring id ({@link #ID}).
+ */
+public final class RenameKeyDescriptor extends RefactoringDescriptor {
+
+ public static final String ID = "org.eclipse.babel.editor.refactoring.renameKey"; //$NON-NLS-1$
+
+ /** The name attribute */
+ private String fNewName;
+
+ private KeyTreeNode fKeyNode;
+
+ private MessagesBundleGroup fMessagesBundleGroup;
+
+ /** Configures if references will be updated */
+ private boolean fRenameChildKeys;
+
+ /**
+ * Creates a new refactoring descriptor.
+ * <p>
+ * Clients should not instantiated this class but use {@link RefactoringCore#getRefactoringContribution(String)}
+ * with {@link #ID} to get the contribution that can create the descriptor.
+ * </p>
+ */
+ public RenameKeyDescriptor() {
+ super(ID, null, "N/A", null, RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE);
+ fNewName = null;
+ }
+
+ /**
+ * Sets the new name to rename the resource to.
+ *
+ * @param name
+ * the non-empty new name to set
+ */
+ public void setNewName(final String name) {
+ Assert.isNotNull(name);
+ Assert.isLegal(!"".equals(name), "Name must not be empty"); //$NON-NLS-1$//$NON-NLS-2$
+ fNewName = name;
+ }
+
+ /**
+ * Returns the new name to rename the resource to.
+ *
+ * @return
+ * the new name to rename the resource to
+ */
+ public String getNewName() {
+ return fNewName;
+ }
+
+ /**
+ * Sets the project name of this refactoring.
+ * <p>
+ * Note: If the resource to be renamed is of type {@link IResource#PROJECT},
+ * clients are required to to set the project name to <code>null</code>.
+ * </p>
+ * <p>
+ * The default is to associate the refactoring with the workspace.
+ * </p>
+ *
+ * @param project
+ * the non-empty project name to set, or <code>null</code> for
+ * the workspace
+ *
+ * @see #getProject()
+ */
+// public void setProject(final String project) {
+// super.setProject(project);
+// }
+
+ /**
+ * If set to <code>true</code>, this rename will also rename child keys. The default is to rename child keys.
+ *
+ * @param renameChildKeys <code>true</code> if this rename will rename child keys
+ */
+ public void setRenameChildKeys(boolean renameChildKeys) {
+ fRenameChildKeys = renameChildKeys;
+ }
+
+ public void setRenameChildKeys(KeyTreeNode keyNode, MessagesBundleGroup messagesBundleGroup) {
+ this.fKeyNode = keyNode;
+ this.fMessagesBundleGroup = messagesBundleGroup;
+ }
+
+ /**
+ * Returns if this rename will also rename child keys
+ *
+ * @return returns <code>true</code> if this rename will rename child keys
+ */
+ public boolean isRenameChildKeys() {
+ return fRenameChildKeys;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.RefactoringDescriptor#createRefactoring(org.eclipse.ltk.core.refactoring.RefactoringStatus)
+ */
+ public Refactoring createRefactoring(RefactoringStatus status) throws CoreException {
+
+ String newName= getNewName();
+ if (newName == null || newName.length() == 0) {
+ status.addFatalError("The rename resource bundle key refactoring can not be performed as the new name is invalid");
+ return null;
+ }
+ RenameKeyProcessor processor = new RenameKeyProcessor(fKeyNode, fMessagesBundleGroup);
+ processor.setNewResourceName(newName);
+ processor.setRenameChildKeys(fRenameChildKeys);
+
+ return new RenameRefactoring(processor);
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java
new file mode 100644
index 0000000..9c21f6d
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nigel Westbury
+ * 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:
+ * Nigel Westbury - initial implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.refactoring;
+
+import java.text.MessageFormat;
+
+import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
+import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
+import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
+import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
+import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
+import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
+
+/**
+ * A rename processor for {@link IResource}. The processor will rename the resource and
+ * load rename participants if references should be renamed as well.
+ *
+ * @since 3.4
+ */
+public class RenameKeyProcessor extends RenameProcessor {
+
+ private KeyTreeNode fKeyNode;
+
+ private MessagesBundleGroup fMessageBundleGroup;
+
+ private String fNewResourceName;
+
+ private boolean fRenameChildKeys;
+
+ private RenameKeyArguments fRenameArguments; // set after checkFinalConditions
+
+ /**
+ * Creates a new rename resource processor.
+ *
+ * @param keyNode the resource to rename.
+ * @param messagesBundleGroup
+ */
+ public RenameKeyProcessor(KeyTreeNode keyNode, MessagesBundleGroup messagesBundleGroup) {
+ if (keyNode == null) {
+ throw new IllegalArgumentException("key node must not be null"); //$NON-NLS-1$
+ }
+
+ fKeyNode = keyNode;
+ fMessageBundleGroup = messagesBundleGroup;
+ fRenameArguments= null;
+ fRenameChildKeys= true;
+ setNewResourceName(keyNode.getMessageKey()); // Initialize new name
+ }
+
+ /**
+ * Returns the new key node
+ *
+ * @return the new key node
+ */
+ public KeyTreeNode getNewKeyTreeNode() {
+ return fKeyNode;
+ }
+
+ /**
+ * Returns the new resource name
+ *
+ * @return the new resource name
+ */
+ public String getNewResourceName() {
+ return fNewResourceName;
+ }
+
+ /**
+ * Sets the new resource name
+ *
+ * @param newName the new resource name
+ */
+ public void setNewResourceName(String newName) {
+ Assert.isNotNull(newName);
+ fNewResourceName= newName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
+ /*
+ * This method allows fatal and non-fatal problems to be shown to
+ * the user. Currently there are none so we return null to indicate
+ * this.
+ */
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor, org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext)
+ */
+ public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ try {
+ fRenameArguments = new RenameKeyArguments(getNewResourceName(), fRenameChildKeys, false);
+
+ ResourceChangeChecker checker = (ResourceChangeChecker) context.getChecker(ResourceChangeChecker.class);
+ IResourceChangeDescriptionFactory deltaFactory = checker.getDeltaFactory();
+
+ // TODO figure out what we want to do here....
+// ResourceModifications.buildMoveDelta(deltaFactory, fKeyNode, fRenameArguments);
+
+ return new RefactoringStatus();
+ } finally {
+ pm.done();
+ }
+ }
+
+ /**
+ * Validates if the a name is valid. This method does not change the name settings on the refactoring. It is intended to be used
+ * in a wizard to validate user input.
+ *
+ * @param newName the name to validate
+ * @return returns the resulting status of the validation
+ */
+ public RefactoringStatus validateNewElementName(String newName) {
+ Assert.isNotNull(newName);
+
+ if (newName.startsWith(".")) {
+ return RefactoringStatus.createFatalErrorStatus("Key cannot start with a '.'");
+ }
+ if (newName.endsWith(".")) {
+ return RefactoringStatus.createFatalErrorStatus("Key cannot end with a '.'");
+ }
+
+ String [] parts = newName.split("\\.");
+ for (String part : parts) {
+ if (part.length() == 0) {
+ return RefactoringStatus.createFatalErrorStatus("Key cannot contain an empty part between two periods");
+ }
+ if (!part.matches("([A-Z]|[a-z]|[0-9])*")) {
+ return RefactoringStatus.createFatalErrorStatus("Key can contain only letters, digits, and periods");
+ }
+ }
+
+ if (fMessageBundleGroup.isMessageKey(newName)) {
+ return RefactoringStatus.createFatalErrorStatus(MessagesEditorPlugin.getString("dialog.error.exists"));
+ }
+
+ return new RefactoringStatus();
+ }
+
+ protected RenameKeyDescriptor createDescriptor() {
+ RenameKeyDescriptor descriptor= new RenameKeyDescriptor();
+ descriptor.setDescription(MessageFormat.format("Rename resource bundle key ''{0}''", fKeyNode.getMessageKey()));
+ descriptor.setComment(MessageFormat.format("Rename resource ''{0}'' to ''{1}''", new Object[] { fKeyNode.getMessageKey(), fNewResourceName }));
+ descriptor.setFlags(RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE | RefactoringDescriptor.BREAKING_CHANGE);
+ descriptor.setNewName(getNewResourceName());
+ descriptor.setRenameChildKeys(fRenameChildKeys);
+ return descriptor;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#createChange(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public Change createChange(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ try {
+ RenameKeyChange change = new RenameKeyChange(fMessageBundleGroup, getNewKeyTreeNode(), fNewResourceName, fRenameChildKeys);
+ change.setDescriptor(new RefactoringChangeDescriptor(createDescriptor()));
+ return change;
+ } finally {
+ pm.done();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getElements()
+ */
+ public Object[] getElements() {
+ return new Object[] { fKeyNode };
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getIdentifier()
+ */
+ public String getIdentifier() {
+ return "org.eclipse.babel.editor.refactoring.renameKeyProcessor"; //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getProcessorName()
+ */
+ public String getProcessorName() {
+ return "Rename Resource Bundle Key";
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#isApplicable()
+ */
+ public boolean isApplicable() {
+ if (this.fKeyNode == null)
+ return false;
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#loadParticipants(org.eclipse.ltk.core.refactoring.RefactoringStatus, org.eclipse.ltk.core.refactoring.participants.SharableParticipants)
+ */
+ public RefactoringParticipant[] loadParticipants(RefactoringStatus status, SharableParticipants shared) throws CoreException {
+ // TODO: figure out participants to return here
+ return new RefactoringParticipant[0];
+
+// String[] affectedNatures= ResourceProcessors.computeAffectedNatures(fResource);
+// return ParticipantManager.loadRenameParticipants(status, this, fResource, fRenameArguments, null, affectedNatures, shared);
+ }
+
+ /**
+ * Returns <code>true</code> if the refactoring processor also renames the child keys
+ *
+ * @return <code>true</code> if the refactoring processor also renames the child keys
+ */
+ public boolean getRenameChildKeys() {
+ return fRenameChildKeys;
+ }
+
+ /**
+ * Specifies if the refactoring processor also updates the child keys.
+ * The default behaviour is to update the child keys.
+ *
+ * @param renameChildKeys <code>true</code> if the refactoring processor should also rename the child keys
+ */
+ public void setRenameChildKeys(boolean renameChildKeys) {
+ fRenameChildKeys = renameChildKeys;
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java
new file mode 100644
index 0000000..6683545
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Nigel Westbury
+ * 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:
+ * Nigel Westbury - initial implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.refactoring;
+
+import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
+import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * A wizard for the rename bundle key refactoring.
+ */
+public class RenameKeyWizard extends RefactoringWizard {
+
+ /**
+ * Creates a {@link RenameKeyWizard}.
+ *
+ * @param resource
+ * the bundle key to rename
+ * @param refactoring
+ */
+ public RenameKeyWizard(KeyTreeNode resource, RenameKeyProcessor refactoring) {
+ super(new RenameRefactoring(refactoring), DIALOG_BASED_USER_INTERFACE);
+ setDefaultPageTitle("Rename Resource Bundle Key");
+ setWindowTitle("Rename Resource Bundle Key");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.ui.refactoring.RefactoringWizard#addUserInputPages()
+ */
+ protected void addUserInputPages() {
+ RenameKeyProcessor processor = (RenameKeyProcessor) getRefactoring().getAdapter(RenameKeyProcessor.class);
+ addPage(new RenameResourceRefactoringConfigurationPage(processor));
+ }
+
+ private static class RenameResourceRefactoringConfigurationPage extends UserInputWizardPage {
+
+ private final RenameKeyProcessor fRefactoringProcessor;
+ private Text fNameField;
+
+ public RenameResourceRefactoringConfigurationPage(RenameKeyProcessor processor) {
+ super("RenameResourceRefactoringInputPage"); //$NON-NLS-1$
+ fRefactoringProcessor= processor;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ composite.setFont(parent.getFont());
+
+ Label label = new Label(composite, SWT.NONE);
+ label.setText("New name:");
+ label.setLayoutData(new GridData());
+
+ fNameField = new Text(composite, SWT.BORDER);
+ fNameField.setText(fRefactoringProcessor.getNewResourceName());
+ fNameField.setFont(composite.getFont());
+ fNameField.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ fNameField.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validatePage();
+ }
+ });
+
+ final Button includeChildKeysCheckbox = new Button(composite, SWT.CHECK);
+ if (fRefactoringProcessor.getNewKeyTreeNode().isUsedAsKey()) {
+ if (fRefactoringProcessor.getNewKeyTreeNode().getChildren().length == 0) {
+ // This is an actual key with no child keys.
+ includeChildKeysCheckbox.setSelection(false);
+ includeChildKeysCheckbox.setEnabled(false);
+ } else {
+ // This is both an actual key and it has child keys, so we
+ // let the user choose whether to also rename the child keys.
+ includeChildKeysCheckbox.setSelection(fRefactoringProcessor.getRenameChildKeys());
+ includeChildKeysCheckbox.setEnabled(true);
+ }
+ } else {
+ // This is no an actual key, just a containing node, so the option
+ // to rename child keys must be set (otherwise this rename would not
+ // do anything).
+ includeChildKeysCheckbox.setSelection(true);
+ includeChildKeysCheckbox.setEnabled(false);
+ }
+
+ includeChildKeysCheckbox.setText("Also rename child keys (other keys with this key as a prefix)");
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan= 2;
+ includeChildKeysCheckbox.setLayoutData(gd);
+ includeChildKeysCheckbox.addSelectionListener(new SelectionAdapter(){
+ public void widgetSelected(SelectionEvent e) {
+ fRefactoringProcessor.setRenameChildKeys(includeChildKeysCheckbox.getSelection());
+ }
+ });
+
+ fNameField.selectAll();
+ setPageComplete(false);
+ setControl(composite);
+ }
+
+ public void setVisible(boolean visible) {
+ if (visible) {
+ fNameField.setFocus();
+ }
+ super.setVisible(visible);
+ }
+
+ protected final void validatePage() {
+ String text= fNameField.getText();
+ RefactoringStatus status= fRefactoringProcessor.validateNewElementName(text);
+ setPageComplete(status);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.ui.refactoring.UserInputWizardPage#performFinish()
+ */
+ protected boolean performFinish() {
+ initializeRefactoring();
+ storeSettings();
+ return super.performFinish();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ltk.ui.refactoring.UserInputWizardPage#getNextPage()
+ */
+ public IWizardPage getNextPage() {
+ initializeRefactoring();
+ storeSettings();
+ return super.getNextPage();
+ }
+
+ private void storeSettings() {
+ }
+
+ private void initializeRefactoring() {
+ fRefactoringProcessor.setNewResourceName(fNameField.getText());
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java
index 928dec2..b413a44 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java
@@ -19,6 +19,7 @@
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
@@ -130,9 +131,18 @@
* @see org.eclipse.babel.core.bundle.resource.TextResource#setText(
* java.lang.String)
*/
- public void setText(String content) {
- textEditor.getDocumentProvider().getDocument(
- textEditor.getEditorInput()).set(content);
+ public void setText(final String content) {
+ /*
+ * We may come in from an event from another thread, so ensure
+ * we are on the UI thread. This may not be the best place to do
+ * this???
+ */
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ textEditor.getDocumentProvider().getDocument(
+ textEditor.getEditorInput()).set(content);
+ }
+ });
}
/**
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java
index 05e674e..3a4a704 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java
@@ -10,8 +10,12 @@
******************************************************************************/
package org.eclipse.babel.editor.tree;
-import org.eclipse.babel.core.message.tree.DefaultKeyTreeModel;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.tree.visitor.IKeyTreeVisitor;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
@@ -23,7 +27,7 @@
*/
public class KeyTreeContentProvider implements ITreeContentProvider {
- private DefaultKeyTreeModel keyTreeModel;
+ private AbstractKeyTreeModel keyTreeModel;
private Viewer viewer;
private TreeType treeType;
@@ -90,17 +94,21 @@
* getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
- switch (treeType) {
+ switch (treeType) {
case Tree:
return keyTreeModel.getRootNodes();
case Flat:
-// List<KeyTreeNode> results = new ArrayList<KeyTreeNode>();
-// for (KeyTreeNode rootNode : keyTreeModel.getRootNodes()) {
-// results.addAll(Arrays.asList(keyTreeModel.getBranch(rootNode)));
-// }
-// return keyTreeModel.getBranch(keyTreeModel.getRootNode()); // results.toArray();
- return keyTreeModel.getRootNode().getDescendants().toArray();
- default:
+ final Collection<KeyTreeNode> actualKeys = new ArrayList<KeyTreeNode>();
+ IKeyTreeVisitor visitor = new IKeyTreeVisitor() {
+ public void visitKeyTreeNode(KeyTreeNode node) {
+ if (node.isUsedAsKey()) {
+ actualKeys.add(node);
+ }
+ }
+ };
+ keyTreeModel.accept(visitor, keyTreeModel.getRootNode());
+ return actualKeys.toArray();
+ default:
// Should not happen
return new KeyTreeNode[0];
}
@@ -118,7 +126,7 @@
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.viewer = (TreeViewer) viewer;
- this.keyTreeModel = (DefaultKeyTreeModel) newInput;
+ this.keyTreeModel = (AbstractKeyTreeModel) newInput;
}
public TreeType getTreeType() {
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java
index 0714bc9..cffe1be 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java
@@ -14,7 +14,6 @@
import java.util.Observer;
import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.core.message.tree.DefaultKeyTreeModel;
import org.eclipse.babel.core.message.tree.IKeyTreeModelListener;
import org.eclipse.babel.core.message.tree.KeyTreeNode;
import org.eclipse.babel.editor.IMessagesEditorChangeListener;
@@ -39,6 +38,7 @@
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
@@ -58,7 +58,7 @@
public KeyTreeContributor(final MessagesEditor editor) {
super();
this.editor = editor;
- this.treeModel = new DefaultKeyTreeModel(editor.getBundleGroup());
+ this.treeModel = new AbstractKeyTreeModel(editor.getBundleGroup());
this.treeType = TreeType.Tree;
}
@@ -153,7 +153,11 @@
private void contributeMarkers(final TreeViewer treeViewer) {
editor.getMarkers().addObserver(new Observer() {
public void update(Observable o, Object arg) {
- treeViewer.refresh();
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run() {
+ treeViewer.refresh();
+ }
+ });
}
});
// editor.addChangeListener(new MessagesEditorChangeAdapter() {
@@ -228,13 +232,21 @@
final IKeyTreeModelListener keyTreeListener = new IKeyTreeModelListener() {
//TODO be smarter about refreshes.
public void nodeAdded(KeyTreeNode node) {
- treeViewer.refresh(true);
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run() {
+ treeViewer.refresh(true);
+ }
+ });
};
// public void nodeChanged(KeyTreeNode node) {
// treeViewer.refresh(true);
// };
public void nodeRemoved(KeyTreeNode node) {
- treeViewer.refresh(true);
+ Display.getDefault().asyncExec(new Runnable(){
+ public void run() {
+ treeViewer.refresh(true);
+ }
+ });
};
};
treeModel.addKeyTreeModelListener(keyTreeListener);
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java
index 0e3c5d3..2da68f2 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java
@@ -10,15 +10,15 @@
******************************************************************************/
package org.eclipse.babel.editor.tree.actions;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
import org.eclipse.babel.core.message.tree.KeyTreeNode;
import org.eclipse.babel.editor.MessagesEditor;
import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
+import org.eclipse.babel.editor.refactoring.RenameKeyProcessor;
+import org.eclipse.babel.editor.refactoring.RenameKeyWizard;
import org.eclipse.babel.editor.util.UIUtils;
-import org.eclipse.jface.dialogs.IInputValidator;
-import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.window.Window;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
/**
* @author Pascal Essiembre
@@ -42,47 +42,16 @@
*/
public void run() {
KeyTreeNode node = getNodeSelection();
- String key = node.getMessageKey();
- String msgHead = null;
- String msgBody = null;
- if (getContentProvider().hasChildren(node)) {
- msgHead = MessagesEditorPlugin.getString(
- "dialog.rename.head.multiple"); //$NON-NLS-1$
- msgBody = MessagesEditorPlugin.getString(
- "dialog.rename.body.multiple", //$NON-NLS-1$
- key);
- } else {
- msgHead = MessagesEditorPlugin.getString(
- "dialog.rename.head.single"); //$NON-NLS-1$
- msgBody = MessagesEditorPlugin.getString(
- "dialog.rename.body.single", key); //$NON-NLS-1$
- }
+
// Rename single item
- InputDialog dialog = new InputDialog(
- getShell(), msgHead, msgBody, key, new IInputValidator() {
- public String isValid(String newText) {
- if (getBundleGroup().isMessageKey(newText)) {
- return MessagesEditorPlugin.getString(
- "dialog.error.exists");
- }
- return null;
- }
- });
- dialog.open();
- if (dialog.getReturnCode() == Window.OK ) {
- String inputKey = dialog.getValue();
- MessagesBundleGroup messagesBundleGroup = getBundleGroup();
- KeyTreeNode[] branchNodes = getBranchNodes(node);
- for (int i = 0; i < branchNodes.length; i++) {
- KeyTreeNode branchNode = branchNodes[i];
- String oldKey = branchNode.getMessageKey();
- if (oldKey.startsWith(key)) {
- String newKey = inputKey + oldKey.substring(key.length());
- messagesBundleGroup.renameMessageKeys(oldKey, newKey);
- }
- }
- }
+ RenameKeyProcessor refactoring = new RenameKeyProcessor(node, getBundleGroup());
+
+ RefactoringWizard wizard = new RenameKeyWizard(node, refactoring);
+ try {
+ RefactoringWizardOpenOperation operation= new RefactoringWizardOpenOperation(wizard);
+ operation.run(getShell(), "Introduce Indirection");
+ } catch (InterruptedException exception) {
+ // Do nothing
+ }
}
-
-
}