summaryrefslogtreecommitdiff
path: root/src/plugins/preflighting.checkers/src/com/motorolamobility/preflighting/checkers/layout/MissingIdCondition.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/preflighting.checkers/src/com/motorolamobility/preflighting/checkers/layout/MissingIdCondition.java')
-rw-r--r--src/plugins/preflighting.checkers/src/com/motorolamobility/preflighting/checkers/layout/MissingIdCondition.java231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/plugins/preflighting.checkers/src/com/motorolamobility/preflighting/checkers/layout/MissingIdCondition.java b/src/plugins/preflighting.checkers/src/com/motorolamobility/preflighting/checkers/layout/MissingIdCondition.java
new file mode 100644
index 0000000..1c8b27e
--- /dev/null
+++ b/src/plugins/preflighting.checkers/src/com/motorolamobility/preflighting/checkers/layout/MissingIdCondition.java
@@ -0,0 +1,231 @@
+/*
+* Copyright (C) 2012 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.motorolamobility.preflighting.checkers.layout;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.motorolamobility.preflighting.checkers.CheckerPlugin;
+import com.motorolamobility.preflighting.checkers.i18n.CheckerNLS;
+import com.motorolamobility.preflighting.core.applicationdata.ApplicationData;
+import com.motorolamobility.preflighting.core.applicationdata.XMLElement;
+import com.motorolamobility.preflighting.core.checker.condition.CanExecuteConditionStatus;
+import com.motorolamobility.preflighting.core.checker.condition.Condition;
+import com.motorolamobility.preflighting.core.checker.condition.ICondition;
+import com.motorolamobility.preflighting.core.devicespecification.DeviceSpecification;
+import com.motorolamobility.preflighting.core.exception.PreflightingCheckerException;
+import com.motorolamobility.preflighting.core.internal.cond.utils.ConditionUtils;
+import com.motorolamobility.preflighting.core.utils.CheckerUtils;
+import com.motorolamobility.preflighting.core.utils.LayoutConstants;
+import com.motorolamobility.preflighting.core.utils.XmlUtils;
+import com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration;
+import com.motorolamobility.preflighting.core.validation.ValidationResult;
+import com.motorolamobility.preflighting.core.validation.ValidationResultData;
+
+/**
+ * Layout checker condition that verifies if any id declared in a given layout configuration
+ * is missing on another configurations for the declaring layout
+ */
+public class MissingIdCondition extends Condition implements ICondition
+{
+
+ /*
+ * This map keeps all the keys for a given layout e.g. main.xml.
+ * It is used to look for any missing ID.
+ */
+ private HashMap<String, GlobalLayoutId> globalMap;
+
+ private ValidationManagerConfiguration valManagerConfig;
+
+ @Override
+ public CanExecuteConditionStatus canExecute(ApplicationData data,
+ List<DeviceSpecification> deviceSpecs) throws PreflightingCheckerException
+ {
+ CanExecuteConditionStatus status =
+ new CanExecuteConditionStatus(IStatus.OK, CheckerPlugin.PLUGIN_ID, "");
+ status.setConditionId(getId());
+ return status;
+ }
+
+ @Override
+ public void execute(ApplicationData data, List<DeviceSpecification> deviceSpecs,
+ ValidationManagerConfiguration valManagerConfig, ValidationResult results)
+ throws PreflightingCheckerException
+ {
+ List<XMLElement> layoutList = data.getLayoutElements();
+ if (layoutList != null)
+ {
+ this.valManagerConfig = valManagerConfig;
+
+ globalMap = new HashMap<String, GlobalLayoutId>();
+
+ //This map stores the IDs of each layout file.
+ //An instance of LayoutFileIDs is created for each file
+ //and the map associates it to the given layout.
+ //Hence, two files of different configurations but with the same name e.g. main.xml
+ //will be associated under the key "main.xml" on the map.
+ HashMap<String, List<LayoutFileId>> mainMap = new HashMap<String, List<LayoutFileId>>();
+
+ for (XMLElement element : layoutList)
+ {
+ String layoutName = element.getFile().getName();
+
+ //initialize globalMap
+ if (!globalMap.containsKey(layoutName))
+ {
+ globalMap.put(layoutName, new GlobalLayoutId());
+ }
+
+ //search for IDs and saves it in the map
+ HashSet<String> idsList = retriveLayoutIDs(layoutName, element.getDocument());
+
+ if (mainMap.keySet().contains(layoutName))
+ {
+ mainMap.get(layoutName).add(new LayoutFileId(element.getFile(), idsList));
+ }
+ else
+ {
+ List<LayoutFileId> layoutArray = new ArrayList<LayoutFileId>();
+ layoutArray.add(new LayoutFileId(element.getFile(), idsList));
+ mainMap.put(layoutName, layoutArray);
+ }
+ }
+
+ //create the results
+ checkForMissingLayoutIDs(mainMap, results);
+ }
+ }
+
+ /*
+ * Analyze the generated lists and create the results.
+ */
+ private void checkForMissingLayoutIDs(HashMap<String, List<LayoutFileId>> mainMap,
+ ValidationResult results)
+ {
+ //for each layout e.g. main.xml
+ for (String key : mainMap.keySet())
+ {
+ Set<String> currentCompleteIDList = new HashSet<String>();
+ //this is the list of all IDs found for the given layout
+ final Set<String> completeIDList = globalMap.get(key).getIdsList();
+
+ //for each file e.g. any main.xml found inside the layout's directories
+ for (LayoutFileId layout : mainMap.get(key))
+ {
+ currentCompleteIDList.addAll(completeIDList);
+
+ //check if there are missing keys
+ if (!layout.getIdsList().containsAll(currentCompleteIDList))
+ {
+ currentCompleteIDList.removeAll(layout.getIdsList());
+
+ //create the result for each key
+ for (String missingKey : currentCompleteIDList)
+ {
+ ValidationResultData data = new ValidationResultData();
+ data.addFileToIssueLines(layout.getLayoutFile(), new ArrayList<Integer>());
+ data.setConditionID(getId());
+ data.setSeverity(getSeverityLevel());
+ data.setQuickFixSuggestion(CheckerNLS.LayoutChecker_MissingKeyFixSuggestion);
+ data.setPreview(XmlUtils.getXMLNodeAsString(
+ globalMap.get(key).getNode(missingKey), false));
+ data.setIssueDescription(CheckerNLS.bind(
+ CheckerNLS.LayoutChecker_MissingKeyWarningMessage, missingKey));
+ data.setInfoURL(ConditionUtils.getDescriptionLink(getChecker().getId(),
+ getId(), valManagerConfig));
+ results.addValidationResult(data);
+ }
+ }
+ currentCompleteIDList.clear();
+ }
+ }
+ }
+
+ /*
+ * start the visit by the root node
+ */
+ private HashSet<String> retriveLayoutIDs(String layoutName, Document document)
+ {
+ //this is the current layout ID list
+ HashSet<String> idsList = new HashSet<String>();
+ Element rootElem = document.getDocumentElement();
+
+ String rootId = rootElem.getAttribute(LayoutConstants.ANDROID_ID_ATTRIBUTE);
+ rootId = CheckerUtils.getIdValue(rootId.trim());
+ if (rootId.length() > 0)
+ {
+ //add the ID to local and global list
+ idsList.add(rootId);
+ globalMap.get(layoutName).addID(rootId, rootElem);
+ }
+
+ //visit children
+ NodeList nodeList = rootElem.getChildNodes();
+ for (int i = 0; i < nodeList.getLength(); i++)
+ {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ visitNode(layoutName, node, idsList);
+ }
+ }
+
+ return idsList;
+ }
+
+ /**
+ * Visit nodes recursively, retrieving its IDs.
+ */
+ private void visitNode(String layoutName, Node node, HashSet<String> idsList)
+ {
+ NamedNodeMap map = node.getAttributes();
+ Node attribute = map.getNamedItem(LayoutConstants.ANDROID_ID_ATTRIBUTE);
+
+ if (attribute != null)
+ {
+ String id = attribute.getTextContent();
+ id = CheckerUtils.getIdValue(id.trim());
+ if (id.length() > 0)
+ {
+ //add the ID to local and global list
+ idsList.add(id);
+ globalMap.get(layoutName).addID(id, node);
+ }
+ }
+
+ //visit children
+ NodeList nodeList = node.getChildNodes();
+ for (int i = 0; i < nodeList.getLength(); i++)
+ {
+ Node childNode = nodeList.item(i);
+ if (childNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ visitNode(layoutName, childNode, idsList);
+ }
+ }
+ }
+
+}