Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Fedorov2019-05-13 15:57:58 +0000
committerJulian Honnen2019-05-15 10:34:18 +0000
commitd78de91bf5e6a376f1077823af759faa356161f5 (patch)
tree955671a121acd2a42110291d066321baa5d41f2c
parentf78e921f52642545aaea9251961eed2dde5bc99b (diff)
downloadeclipse.pde.ui-d78de91bf5e6a376f1077823af759faa356161f5.tar.gz
eclipse.pde.ui-d78de91bf5e6a376f1077823af759faa356161f5.tar.xz
eclipse.pde.ui-d78de91bf5e6a376f1077823af759faa356161f5.zip
Bug 547222 - [category] Allow to edit feature properties
Change-Id: I61b07dc91ee8f3c42f4148474cf070744a390084 Signed-off-by: Alexander Fedorov <alexander.fedorov@arsysop.ru> Signed-off-by: Julian Honnen <julian.honnen@vector.com>
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java10
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/CategorySection.java3
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/FeatureDetailsSection.java308
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/IUsPage.java50
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/SiteFeatureAdapter.java52
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties9
6 files changed, 381 insertions, 51 deletions
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
index d2d800e2c5..9b4e3011b1 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/PDEUIMessages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014, 2018 IBM Corporation and others.
+ * Copyright (c) 2014, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -16,6 +16,7 @@
* Martin Karpisek <martin.karpisek@gmail.com> - Bug 438509
* Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes
* Kit Lo (IBM) - Bug 244461 - Duplicating colon in error message
+ * Alexander Fedorov <alexander.fedorov@arsysop.ru> - Bug 547222
*******************************************************************************/
package org.eclipse.pde.internal.ui;
@@ -1924,6 +1925,13 @@ public class PDEUIMessages extends NLS {
public static String CategoryDetails_alreadyExists;
public static String CategoryDetails_alreadyExists_title;
+ public static String FeatureDetails_title;
+ public static String FeatureDetails_sectionDescription;
+ public static String FeatureDetails_id;
+ public static String FeatureDetails_version;
+ public static String FeatureDetails_url;
+ public static String FeatureDetails_include_url;
+
public static String FeaturesPage_title;
public static String FeaturesPage_header;
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/CategorySection.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/CategorySection.java
index a7d369ca56..796c8612b6 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/CategorySection.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/CategorySection.java
@@ -685,7 +685,8 @@ public class CategorySection extends TreeSection implements IFeatureModelListene
ISiteFeature featureCopy = adapter.feature;
ISiteFeature[] features = fModel.getSite().getFeatures();
for (ISiteFeature feature : features) {
- if (feature.getId().equals(featureCopy.getId()) && feature.getVersion().equals(featureCopy.getVersion())) {
+ if (Objects.equals(feature.getId(), featureCopy.getId())
+ && Objects.equals(feature.getVersion(), featureCopy.getVersion())) {
return feature;
}
}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/FeatureDetailsSection.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/FeatureDetailsSection.java
new file mode 100644
index 0000000000..e72b3fe384
--- /dev/null
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/FeatureDetailsSection.java
@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * Copyright (c) 2019 ArSysOp and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Alexander Fedorov <alexander.fedorov@arsysop.ru> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.internal.ui.editor.category;
+
+import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.pde.core.IModelChangedEvent;
+import org.eclipse.pde.internal.core.isite.ISiteFeature;
+import org.eclipse.pde.internal.core.isite.ISiteModel;
+import org.eclipse.pde.internal.ui.PDEPlugin;
+import org.eclipse.pde.internal.ui.PDEUIMessages;
+import org.eclipse.pde.internal.ui.editor.*;
+import org.eclipse.pde.internal.ui.parts.FormEntry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.*;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.forms.IFormPart;
+import org.eclipse.ui.forms.IPartSelectionListener;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.Section;
+import org.osgi.framework.Version;
+
+public class FeatureDetailsSection extends PDESection implements IPartSelectionListener {
+
+ private static final String PROPERTY_ID = "id"; //$NON-NLS-1$
+ private static final String PROPERTY_VERSION = "version"; //$NON-NLS-1$
+ private static final String PROPERTY_URL = "url"; //$NON-NLS-1$
+
+ private ISiteFeature fCurrentSiteFeature;
+ private FormEntry fIdText;
+ private FormEntry fVersionText;
+ private FormEntry fUrlText;
+ private Button fIncludeUrlCheckbox;
+ private SelectionListener fRecomputeAdapter;
+
+ public FeatureDetailsSection(PDEFormPage page, Composite parent) {
+ this(page, parent, PDEUIMessages.FeatureDetails_title, PDEUIMessages.FeatureDetails_sectionDescription,
+ SWT.NULL);
+
+ }
+
+ public FeatureDetailsSection(PDEFormPage page, Composite parent, String title, String desc, int toggleStyle) {
+ super(page, parent, Section.DESCRIPTION | toggleStyle);
+ getSection().setText(title);
+ getSection().setDescription(desc);
+ createClient(getSection(), page.getManagedForm().getToolkit());
+ }
+
+ private void applyValue(String property, String value) throws CoreException {
+ if (fCurrentSiteFeature == null) {
+ return;
+ }
+ if (property.equals(PROPERTY_ID)) {
+ fCurrentSiteFeature.setId(value);
+ } else if (property.equals(PROPERTY_VERSION)) {
+ fCurrentSiteFeature.setVersion(value);
+ } else if (property.equals(PROPERTY_URL)) {
+ fCurrentSiteFeature.setURL(value);
+ }
+ }
+
+ @Override
+ public void cancelEdit() {
+ fIdText.cancelEdit();
+ fVersionText.cancelEdit();
+ super.cancelEdit();
+ }
+
+ @Override
+ public boolean canPaste(Clipboard clipboard) {
+ TransferData[] types = clipboard.getAvailableTypes();
+ Transfer[] transfers = new Transfer[] {TextTransfer.getInstance(), RTFTransfer.getInstance()};
+ for (TransferData type : types) {
+ for (Transfer transfer : transfers) {
+ if (transfer.isSupportedType(type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void clearField(String property) {
+ if (property.equals(PROPERTY_ID)) {
+ fIdText.setValue(null, true);
+ } else if (property.equals(PROPERTY_VERSION)) {
+ fVersionText.setValue(null, true);
+ } else if (property.equals(PROPERTY_URL)) {
+ fUrlText.setValue(null, true);
+ fIncludeUrlCheckbox.setSelection(false);
+ }
+ }
+
+ private void clearFields() {
+ fIdText.setValue(null, true);
+ fVersionText.setValue(null, true);
+ fUrlText.setValue(null, true);
+ fIncludeUrlCheckbox.setSelection(false);
+ }
+
+ @Override
+ public void commit(boolean onSave) {
+ fIdText.commit();
+ fVersionText.commit();
+ super.commit(onSave);
+ }
+
+ @Override
+ public void createClient(Section section, FormToolkit toolkit) {
+ section.setLayout(FormLayoutFactory.createClearGridLayout(false, 1));
+ Composite container = toolkit.createComposite(section);
+ container.setLayout(FormLayoutFactory.createSectionClientGridLayout(false, 2));
+ container.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ GridData data = new GridData(GridData.FILL_BOTH);
+ section.setLayoutData(data);
+
+ fIdText = new FormEntry(container, toolkit, PDEUIMessages.FeatureDetails_id, null, false);
+ fIdText.setFormEntryListener(new FormEntryAdapter(this) {
+ @Override
+ public void textValueChanged(FormEntry text) {
+ try {
+ applyValue(PROPERTY_ID, text.getValue());
+ if (fIncludeUrlCheckbox.getSelection()) {
+ applyUrl(true);
+ }
+ } catch (CoreException e) {
+ PDEPlugin.logException(e);
+ }
+ }
+ });
+ limitTextWidth(fIdText);
+ fIdText.setEditable(isEditable());
+
+ fVersionText = new FormEntry(container, toolkit, PDEUIMessages.FeatureDetails_version, null, false);
+ fVersionText.setFormEntryListener(new FormEntryAdapter(this) {
+
+ @Override
+ public void textValueChanged(FormEntry text) {
+ applyVersion(text.getValue());
+ if (fIncludeUrlCheckbox.getSelection()) {
+ applyUrl(true);
+ }
+ }
+
+ });
+ limitTextWidth(fVersionText);
+ fVersionText.setEditable(isEditable());
+
+ fUrlText = new FormEntry(container, toolkit, PDEUIMessages.FeatureDetails_url, null, false);
+ limitTextWidth(fUrlText);
+ fUrlText.setEditable(false);
+
+ toolkit.createLabel(container, ""); //$NON-NLS-1$
+ fIncludeUrlCheckbox = toolkit.createButton(container, PDEUIMessages.FeatureDetails_include_url, SWT.CHECK);
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalIndent = FormLayoutFactory.CONTROL_HORIZONTAL_INDENT;
+ fIncludeUrlCheckbox.setLayoutData(gd);
+ fRecomputeAdapter = widgetSelectedAdapter(e -> applyUrl(fIncludeUrlCheckbox.getSelection()));
+ fIncludeUrlCheckbox.addSelectionListener(fRecomputeAdapter);
+ fIncludeUrlCheckbox.setEnabled(isEditable());
+
+ toolkit.paintBordersFor(container);
+ section.setClient(container);
+
+ ISiteModel model = (ISiteModel) getPage().getModel();
+ if (model != null) {
+ model.addModelChangedListener(this);
+ }
+ }
+
+ private void applyVersion(String version) {
+ String value = version;
+ if (value != null && value.isEmpty()) {
+ // do not store empty version
+ value = null;
+ }
+ if (value == null) {
+ applyUrl(false);
+ }
+ try {
+ applyValue(PROPERTY_VERSION, value);
+ } catch (CoreException e) {
+ PDEPlugin.logException(e);
+ }
+
+ updateUrlEnablement();
+ }
+
+ private void applyUrl(boolean include) {
+ String value = include ? recomputeUrl() : null;
+ try {
+ applyValue(PROPERTY_URL, value);
+ } catch (CoreException e) {
+ PDEPlugin.logException(e);
+ }
+ }
+
+ private String recomputeUrl() {
+ if (fCurrentSiteFeature == null) {
+ return null;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("features/").append(fCurrentSiteFeature.getId()).append("_"); //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ sb.append(new Version(fCurrentSiteFeature.getVersion()));
+ } catch (Exception e) {
+ sb.append("0.0.0"); //$NON-NLS-1$
+ }
+ sb.append(".jar"); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+ private void updateUrlEnablement() {
+ fIncludeUrlCheckbox.setEnabled(isEditable() && !fVersionText.getValue().isEmpty());
+ }
+
+ @Override
+ public void dispose() {
+ ISiteModel model = (ISiteModel) getPage().getModel();
+ if (model != null) {
+ model.removeModelChangedListener(this);
+ }
+ super.dispose();
+ }
+
+ private void limitTextWidth(FormEntry entry) {
+ GridData gd = (GridData) entry.getText().getLayoutData();
+ gd.widthHint = 30;
+ }
+
+ @Override
+ public void modelChanged(IModelChangedEvent e) {
+ markStale();
+ }
+
+ @Override
+ public void refresh() {
+ if (fCurrentSiteFeature == null) {
+ clearFields();
+ super.refresh();
+ return;
+ }
+ setValue(PROPERTY_ID);
+ setValue(PROPERTY_VERSION);
+ setValue(PROPERTY_URL);
+ updateUrlEnablement();
+ super.refresh();
+ }
+
+ @Override
+ public void selectionChanged(IFormPart part, ISelection selection) {
+ ISiteFeature siteFeature = null;
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection structured = (IStructuredSelection) selection;
+ Object o = structured.getFirstElement();
+ if (o instanceof ISiteFeature) {
+ siteFeature = (ISiteFeature) o;
+ } else if (o instanceof SiteFeatureAdapter) {
+ siteFeature = ((SiteFeatureAdapter) o).feature;
+ }
+ }
+ fCurrentSiteFeature = siteFeature;
+ refresh();
+ }
+
+ @Override
+ public void setFocus() {
+ if (fIdText != null) {
+ fIdText.getText().setFocus();
+ }
+ }
+
+ private void setValue(String property) {
+ if (fCurrentSiteFeature == null) {
+ clearField(property);
+ } else {
+ if (property.equals(PROPERTY_ID)) {
+ fIdText.setValue(fCurrentSiteFeature.getId(), true);
+ } else if (property.equals(PROPERTY_VERSION)) {
+ fVersionText.setValue(fCurrentSiteFeature.getVersion(), true);
+ } else if (property.equals(PROPERTY_URL)) {
+ fIncludeUrlCheckbox.removeSelectionListener(fRecomputeAdapter);
+ String url = fCurrentSiteFeature.getURL();
+ fIncludeUrlCheckbox.setSelection(url != null);
+ fUrlText.setValue(url, true);
+ fIncludeUrlCheckbox.addSelectionListener(fRecomputeAdapter);
+ }
+ }
+ }
+}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/IUsPage.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/IUsPage.java
index 5c0773c004..3ff21fc4d4 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/IUsPage.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/IUsPage.java
@@ -1,21 +1,24 @@
/*******************************************************************************
-.
-. This
-* program and the accompanying materials are made available under the terms of
-* the Eclipse Public License 2.0 which accompanies this distribution, and is
-t https://www.eclipse.org/legal/epl-2.0/
-t
-t SPDX-License-Identifier: EPL-2.0
-*
-* Contributors:
-* EclipseSource - initial API and implementation
-* IBM Corporation - Renamed from FeaturesPage
-* Red Hat Inc. - Support for nested categories
-* Martin Karpisek <martin.karpisek@gmail.com> - Bug 296392
-******************************************************************************/
+ * Copyright (c) 2009, 2019 EclipseSource and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ * IBM Corporation - Renamed from FeaturesPage
+ * Red Hat Inc. - Support for nested categories
+ * Martin Karpisek <martin.karpisek@gmail.com> - Bug 296392
+ * Alexander Fedorov <alexander.fedorov@arsysop.ru> - Bug 547222
+ ******************************************************************************/
package org.eclipse.pde.internal.ui.editor.category;
import org.eclipse.pde.internal.core.isite.ISiteCategoryDefinition;
+import org.eclipse.pde.internal.core.isite.ISiteFeature;
import org.eclipse.pde.internal.ui.*;
import org.eclipse.pde.internal.ui.editor.*;
import org.eclipse.swt.widgets.Composite;
@@ -60,8 +63,11 @@ public class IUsPage extends PDEFormPage {
@Override
public IDetailsPage getPage(Object key) {
- if (key.equals(ISiteCategoryDefinition.class) || key.equals(SiteCategoryDefinitionAdapter.class))
+ if (key.equals(ISiteCategoryDefinition.class) || key.equals(SiteCategoryDefinitionAdapter.class)) {
return createCategoryDetails();
+ } else if (key.equals(ISiteFeature.class) || key.equals(SiteFeatureAdapter.class)) {
+ return createFeatureDetails();
+ }
return null;
}
});
@@ -98,6 +104,20 @@ public class IUsPage extends PDEFormPage {
};
}
+ private IDetailsPage createFeatureDetails() {
+ return new PDEDetailsSections() {
+ @Override
+ protected PDESection[] createSections(PDEFormPage page, Composite parent) {
+ return new PDESection[] { new FeatureDetailsSection(getPage(), parent) };
+ }
+
+ @Override
+ public String getContextId() {
+ return CategoryInputContext.CONTEXT_ID;
+ }
+ };
+ }
+
@Override
protected String getHelpResource() {
return IHelpContextIds.CATEGORY_EDITOR;
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/SiteFeatureAdapter.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/SiteFeatureAdapter.java
index c3c8070a1a..788a154cc8 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/SiteFeatureAdapter.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/category/SiteFeatureAdapter.java
@@ -1,19 +1,22 @@
/*******************************************************************************
-.
-. This
-* program and the accompanying materials are made available under the terms of
-* the Eclipse Public License 2.0 which accompanies this distribution, and is
-t https://www.eclipse.org/legal/epl-2.0/
-t
-t SPDX-License-Identifier: EPL-2.0
-*
-* Contributors:
-* EclipseSource - initial API and implementation
-******************************************************************************/
+ * Copyright (c) 2009, 2019 EclipseSource and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * EclipseSource - initial API and implementation
+ * Alexander Fedorov <alexander.fedorov@arsysop.ru> - Bug 547222
+ ******************************************************************************/
package org.eclipse.pde.internal.ui.editor.category;
import java.io.PrintWriter;
import java.io.Serializable;
+import java.util.Objects;
import org.eclipse.pde.core.IWritable;
import org.eclipse.pde.internal.core.isite.ISiteFeature;
@@ -35,8 +38,8 @@ public class SiteFeatureAdapter implements Serializable, IWritable {
}
/*
- * For retaining selectiong in the tree, when modyfing or moving features,
- * SiteFeatureAdapter are equal if features are equal (same ID and version)
+ * For retaining selection in the tree, when modyfing or moving features,
+ * SiteFeatureAdapter are equal if features are equal
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@@ -44,32 +47,13 @@ public class SiteFeatureAdapter implements Serializable, IWritable {
public boolean equals(Object obj) {
if (obj instanceof SiteFeatureAdapter) {
SiteFeatureAdapter adapter = (SiteFeatureAdapter) obj;
- String id = feature.getId();
- String id2 = adapter.feature.getId();
- boolean sameFeature = id != null && id2 != null && id.equals(id2);
- if (sameFeature) {
- String version = feature.getVersion();
- String version2 = adapter.feature.getVersion();
- sameFeature = version != null && version2 != null && version.equals(version2);
- }
- boolean sameCategory = adapter.category != null && category != null ? adapter.category.equals(category) : true;
- return sameFeature && sameCategory;
+ return Objects.equals(feature, adapter.feature);
}
return super.equals(obj);
}
@Override
public int hashCode() {
- if (feature.getId() == null) {
- return super.hashCode();
- }
- int code = feature.getId().hashCode();
- if (feature.getVersion() != null) {
- code += feature.getVersion().hashCode();
- }
- if (category != null) {
- code += category.hashCode();
- }
- return code;
+ return feature.hashCode();
}
}
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
index e8a8131af1..93dd22d2fd 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/pderesources.properties
@@ -18,6 +18,7 @@
# Martin Karpisek <martin.karpisek@gmail.com> - Bug 438509
# Axel Richard (Obeo) - Bug 41353 - Launch configurations prototypes
# Kit Lo (IBM) - Bug 244461 - Duplicating colon in error message
+# Alexander Fedorov <alexander.fedorov@arsysop.ru> - Bug 547222
###############################################################################
#####################################
# PDE resource strings
@@ -1742,6 +1743,14 @@ CategoryDetails_desc = De&scription:
CategoryDetails_alreadyExists=The category must have a unique id.
CategoryDetails_alreadyExists_title = Invalid category id
+FeatureDetails_title = Feature Properties
+FeatureDetails_sectionDescription = Provide an identifier and a version for each feature.\n\
+"*" denotes a required field.
+FeatureDetails_id = &ID*:
+FeatureDetails_version = &Version:
+FeatureDetails_url = URL
+FeatureDetails_include_url=Include URL
+
FeaturesPage_title = Site Map
FeaturesPage_header = Update Site Map

Back to the top