nsRDFConInstanceTestNode.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsIComponentManager.h"
  6. #include "nsIRDFContainer.h"
  7. #include "nsIRDFContainerUtils.h"
  8. #include "nsIServiceManager.h"
  9. #include "nsRDFCID.h"
  10. #include "nsRDFConInstanceTestNode.h"
  11. #include "nsResourceSet.h"
  12. #include "mozilla/Logging.h"
  13. #include "nsXULContentUtils.h"
  14. using mozilla::LogLevel;
  15. extern mozilla::LazyLogModule gXULTemplateLog;
  16. static const char*
  17. TestToString(nsRDFConInstanceTestNode::Test aTest) {
  18. switch (aTest) {
  19. case nsRDFConInstanceTestNode::eFalse: return "false";
  20. case nsRDFConInstanceTestNode::eTrue: return "true";
  21. case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
  22. }
  23. return "?";
  24. }
  25. nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(TestNode* aParent,
  26. nsXULTemplateQueryProcessorRDF* aProcessor,
  27. nsIAtom* aContainerVariable,
  28. Test aContainer,
  29. Test aEmpty)
  30. : nsRDFTestNode(aParent),
  31. mProcessor(aProcessor),
  32. mContainerVariable(aContainerVariable),
  33. mContainer(aContainer),
  34. mEmpty(aEmpty)
  35. {
  36. if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
  37. nsAutoCString props;
  38. nsResourceSet& containmentProps = aProcessor->ContainmentProperties();
  39. nsResourceSet::ConstIterator last = containmentProps.Last();
  40. nsResourceSet::ConstIterator first = containmentProps.First();
  41. nsResourceSet::ConstIterator iter;
  42. for (iter = first; iter != last; ++iter) {
  43. if (iter != first)
  44. props += " ";
  45. const char* str;
  46. iter->GetValueConst(&str);
  47. props += str;
  48. }
  49. nsAutoString cvar(NS_LITERAL_STRING("(none)"));
  50. if (mContainerVariable)
  51. mContainerVariable->ToString(cvar);
  52. MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
  53. ("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%s container=%s empty=%s",
  54. this,
  55. aParent,
  56. props.get(),
  57. NS_ConvertUTF16toUTF8(cvar).get(),
  58. TestToString(aContainer),
  59. TestToString(aEmpty)));
  60. }
  61. }
  62. nsresult
  63. nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations,
  64. bool* aCantHandleYet) const
  65. {
  66. nsresult rv;
  67. if (aCantHandleYet)
  68. *aCantHandleYet = false;
  69. nsCOMPtr<nsIRDFContainerUtils> rdfc
  70. = do_GetService("@mozilla.org/rdf/container-utils;1");
  71. if (! rdfc)
  72. return NS_ERROR_FAILURE;
  73. nsIRDFDataSource* ds = mProcessor->GetDataSource();
  74. InstantiationSet::Iterator last = aInstantiations.Last();
  75. for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
  76. nsCOMPtr<nsIRDFNode> value;
  77. if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, getter_AddRefs(value))) {
  78. NS_ERROR("can't do unbounded container testing");
  79. return NS_ERROR_UNEXPECTED;
  80. }
  81. nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
  82. if (! valueres) {
  83. aInstantiations.Erase(inst--);
  84. continue;
  85. }
  86. if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
  87. const char* container = "(unbound)";
  88. valueres->GetValueConst(&container);
  89. MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
  90. ("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
  91. this, container));
  92. }
  93. nsCOMPtr<nsIRDFContainer> rdfcontainer;
  94. bool isRDFContainer;
  95. rv = rdfc->IsContainer(ds, valueres, &isRDFContainer);
  96. if (NS_FAILED(rv)) return rv;
  97. if (mEmpty != eDontCare || mContainer != eDontCare) {
  98. Test empty = eDontCare;
  99. Test container = eDontCare;
  100. if (isRDFContainer) {
  101. // It's an RDF container. Use the container utilities
  102. // to deduce what's in it.
  103. container = eTrue;
  104. // XXX should cache the factory
  105. rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
  106. if (NS_FAILED(rv)) return rv;
  107. rv = rdfcontainer->Init(ds, valueres);
  108. if (NS_FAILED(rv)) return rv;
  109. int32_t count;
  110. rv = rdfcontainer->GetCount(&count);
  111. if (NS_FAILED(rv)) return rv;
  112. empty = (count == 0) ? eTrue : eFalse;
  113. } else {
  114. empty = eTrue;
  115. container = eFalse;
  116. // First do the simple check of finding some outward
  117. // arcs; there should be only a few containment arcs, so this can
  118. // save us time from dealing with an iterator later on
  119. nsResourceSet& containmentProps = mProcessor->ContainmentProperties();
  120. for (nsResourceSet::ConstIterator property = containmentProps.First();
  121. property != containmentProps.Last();
  122. ++property) {
  123. nsCOMPtr<nsIRDFNode> target;
  124. rv = ds->GetTarget(valueres, *property, true, getter_AddRefs(target));
  125. if (NS_FAILED(rv)) return rv;
  126. if (target != nullptr) {
  127. // bingo. we found one.
  128. empty = eFalse;
  129. container = eTrue;
  130. break;
  131. }
  132. }
  133. // if we still don't think its a container, but we
  134. // want to know for sure whether it is or not, we need
  135. // to check ArcLabelsOut for potential container arcs.
  136. if (container == eFalse && mContainer != eDontCare) {
  137. nsCOMPtr<nsISimpleEnumerator> arcsout;
  138. rv = ds->ArcLabelsOut(valueres, getter_AddRefs(arcsout));
  139. if (NS_FAILED(rv)) return rv;
  140. while (1) {
  141. bool hasmore;
  142. rv = arcsout->HasMoreElements(&hasmore);
  143. if (NS_FAILED(rv)) return rv;
  144. if (! hasmore)
  145. break;
  146. nsCOMPtr<nsISupports> isupports;
  147. rv = arcsout->GetNext(getter_AddRefs(isupports));
  148. if (NS_FAILED(rv)) return rv;
  149. nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
  150. NS_ASSERTION(property != nullptr, "not a property");
  151. if (! property)
  152. return NS_ERROR_UNEXPECTED;
  153. if (mProcessor->ContainmentProperties().Contains(property)) {
  154. container = eTrue;
  155. break;
  156. }
  157. }
  158. }
  159. }
  160. MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
  161. (" empty => %s",
  162. (empty == mEmpty) ? "consistent" : "inconsistent"));
  163. MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
  164. (" container => %s",
  165. (container == mContainer) ? "consistent" : "inconsistent"));
  166. if (((mEmpty == empty) && (mContainer == container)) ||
  167. ((mEmpty == eDontCare) && (mContainer == container)) ||
  168. ((mContainer == eDontCare) && (mEmpty == empty)))
  169. {
  170. Element* element =
  171. new nsRDFConInstanceTestNode::Element(valueres, container, empty);
  172. inst->AddSupportingElement(element);
  173. }
  174. else {
  175. aInstantiations.Erase(inst--);
  176. }
  177. }
  178. }
  179. return NS_OK;
  180. }
  181. bool
  182. nsRDFConInstanceTestNode::CanPropagate(nsIRDFResource* aSource,
  183. nsIRDFResource* aProperty,
  184. nsIRDFNode* aTarget,
  185. Instantiation& aInitialBindings) const
  186. {
  187. nsresult rv;
  188. bool canpropagate = false;
  189. nsCOMPtr<nsIRDFContainerUtils> rdfc
  190. = do_GetService("@mozilla.org/rdf/container-utils;1");
  191. if (! rdfc)
  192. return false;
  193. // We can certainly propagate ordinal properties
  194. rv = rdfc->IsOrdinalProperty(aProperty, &canpropagate);
  195. if (NS_FAILED(rv)) return false;
  196. if (! canpropagate) {
  197. canpropagate = mProcessor->ContainmentProperties().Contains(aProperty);
  198. }
  199. if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
  200. const char* source;
  201. aSource->GetValueConst(&source);
  202. const char* property;
  203. aProperty->GetValueConst(&property);
  204. nsAutoString target;
  205. nsXULContentUtils::GetTextForNode(aTarget, target);
  206. MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
  207. ("nsRDFConInstanceTestNode[%p]: CanPropagate([%s]==[%s]=>[%s]) => %s",
  208. this, source, property, NS_ConvertUTF16toUTF8(target).get(),
  209. canpropagate ? "true" : "false"));
  210. }
  211. if (canpropagate) {
  212. aInitialBindings.AddAssignment(mContainerVariable, aSource);
  213. return true;
  214. }
  215. return false;
  216. }
  217. void
  218. nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
  219. nsIRDFResource* aProperty,
  220. nsIRDFNode* aTarget) const
  221. {
  222. // XXXwaterson oof. complicated. figure this out.
  223. if (0) {
  224. mProcessor->RetractElement(Element(aSource, mContainer, mEmpty));
  225. }
  226. }