michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsXULTemplateQueryProcessorRDF.h" michael@0: #include "nsXULTemplateResultRDF.h" michael@0: #include "nsRDFBinding.h" michael@0: michael@0: #ifdef DEBUG michael@0: #include "nsXULContentUtils.h" michael@0: #endif michael@0: michael@0: RDFBindingSet::~RDFBindingSet() michael@0: { michael@0: while (mFirst) { michael@0: RDFBinding* doomed = mFirst; michael@0: mFirst = mFirst->mNext; michael@0: delete doomed; michael@0: } michael@0: michael@0: MOZ_COUNT_DTOR(RDFBindingSet); michael@0: } michael@0: michael@0: nsresult michael@0: RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate) michael@0: { michael@0: RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar); michael@0: if (! newbinding) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: if (mFirst) { michael@0: RDFBinding* binding = mFirst; michael@0: michael@0: while (binding) { michael@0: // the binding is dependant on the calculation of a previous binding michael@0: if (binding->mSubjectVariable == aVar) michael@0: newbinding->mHasDependency = true; michael@0: michael@0: // if the target variable is already used in a binding, ignore it michael@0: // since it won't be useful for anything michael@0: if (binding->mTargetVariable == aVar) { michael@0: delete newbinding; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // add the binding at the end of the list michael@0: if (! binding->mNext) { michael@0: binding->mNext = newbinding; michael@0: break; michael@0: } michael@0: michael@0: binding = binding->mNext; michael@0: } michael@0: } michael@0: else { michael@0: mFirst = newbinding; michael@0: } michael@0: michael@0: mCount++; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject, michael@0: nsIRDFResource* aPredicate, michael@0: nsIRDFNode* aTarget, michael@0: nsIAtom* aMemberVariable, michael@0: nsXULTemplateResultRDF* aResult, michael@0: nsBindingValues& aBindingValues) michael@0: { michael@0: NS_ASSERTION(aBindingValues.GetBindingSet() == this, michael@0: "nsBindingValues not for this RDFBindingSet"); michael@0: NS_PRECONDITION(aResult, "Must have result"); michael@0: michael@0: bool needSync = false; michael@0: nsCOMPtr* valuesArray = aBindingValues.ValuesArray(); michael@0: if (!valuesArray) michael@0: return false; michael@0: michael@0: RDFBinding* binding = mFirst; michael@0: int32_t count = 0; michael@0: michael@0: // QI for proper comparisons just to be safe michael@0: nsCOMPtr subjectnode = do_QueryInterface(aSubject); michael@0: michael@0: // iterate through the bindings looking for ones that would match the RDF michael@0: // nodes that were involved in a change michael@0: nsCOMPtr value; michael@0: while (binding) { michael@0: if (aPredicate == binding->mPredicate) { michael@0: // if the source of the binding is the member variable, optimize michael@0: if (binding->mSubjectVariable == aMemberVariable) { michael@0: valuesArray[count] = aTarget; michael@0: needSync = true; michael@0: } michael@0: else { michael@0: aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); michael@0: if (value == subjectnode) { michael@0: valuesArray[count] = aTarget; michael@0: needSync = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: binding = binding->mNext; michael@0: count++; michael@0: } michael@0: michael@0: return needSync; michael@0: } michael@0: michael@0: void michael@0: RDFBindingSet::AddDependencies(nsIRDFResource* aSubject, michael@0: nsXULTemplateResultRDF* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "Must have result"); michael@0: michael@0: // iterate through the bindings and add binding dependencies to the michael@0: // processor michael@0: michael@0: nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); michael@0: if (! processor) michael@0: return; michael@0: michael@0: nsCOMPtr value; michael@0: michael@0: RDFBinding* binding = mFirst; michael@0: while (binding) { michael@0: aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); michael@0: michael@0: nsCOMPtr valueres = do_QueryInterface(value); michael@0: if (valueres) michael@0: processor->AddBindingDependency(aResult, valueres); michael@0: michael@0: binding = binding->mNext; michael@0: } michael@0: } michael@0: michael@0: void michael@0: RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject, michael@0: nsXULTemplateResultRDF* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "Must have result"); michael@0: michael@0: // iterate through the bindings and remove binding dependencies from the michael@0: // processor michael@0: michael@0: nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); michael@0: if (! processor) michael@0: return; michael@0: michael@0: nsCOMPtr value; michael@0: michael@0: RDFBinding* binding = mFirst; michael@0: while (binding) { michael@0: aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value)); michael@0: michael@0: nsCOMPtr valueres = do_QueryInterface(value); michael@0: if (valueres) michael@0: processor->RemoveBindingDependency(aResult, valueres); michael@0: michael@0: binding = binding->mNext; michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding) michael@0: { michael@0: int32_t idx = 0; michael@0: RDFBinding* binding = mFirst; michael@0: michael@0: while (binding) { michael@0: if (binding->mTargetVariable == aTargetVariable) { michael@0: *aBinding = binding; michael@0: return idx; michael@0: } michael@0: idx++; michael@0: binding = binding->mNext; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: nsBindingValues::~nsBindingValues() michael@0: { michael@0: ClearBindingSet(); michael@0: MOZ_COUNT_DTOR(nsBindingValues); michael@0: } michael@0: michael@0: void michael@0: nsBindingValues::ClearBindingSet() michael@0: { michael@0: if (mBindings && mValues) { michael@0: delete [] mValues; michael@0: mValues = nullptr; michael@0: } michael@0: michael@0: mBindings = nullptr; michael@0: } michael@0: michael@0: nsresult michael@0: nsBindingValues::SetBindingSet(RDFBindingSet* aBindings) michael@0: { michael@0: ClearBindingSet(); michael@0: michael@0: int32_t count = aBindings->Count(); michael@0: if (count) { michael@0: mValues = new nsCOMPtr[count]; michael@0: if (!mValues) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: mBindings = aBindings; michael@0: } michael@0: else { michael@0: mValues = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult, michael@0: nsIAtom* aVar, michael@0: nsIRDFNode** aValue) michael@0: { michael@0: *aValue = nullptr; michael@0: michael@0: // assignments are calculated lazily when asked for. The only issue is michael@0: // when a binding has no value in the RDF graph, it will be checked again michael@0: // every time. michael@0: michael@0: if (mBindings && mValues) { michael@0: RDFBinding* binding; michael@0: int32_t idx = mBindings->LookupTargetIndex(aVar, &binding); michael@0: if (idx >= 0) { michael@0: *aValue = mValues[idx]; michael@0: if (*aValue) { michael@0: NS_ADDREF(*aValue); michael@0: } michael@0: else { michael@0: nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor(); michael@0: if (! processor) michael@0: return; michael@0: michael@0: nsIRDFDataSource* ds = processor->GetDataSource(); michael@0: if (! ds) michael@0: return; michael@0: michael@0: nsCOMPtr subjectValue; michael@0: aResult->GetAssignment(binding->mSubjectVariable, michael@0: getter_AddRefs(subjectValue)); michael@0: if (subjectValue) { michael@0: nsCOMPtr subject = do_QueryInterface(subjectValue); michael@0: ds->GetTarget(subject, binding->mPredicate, true, aValue); michael@0: if (*aValue) michael@0: mValues[idx] = *aValue; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject, michael@0: nsXULTemplateResultRDF* aResult) michael@0: { michael@0: if (mBindings) michael@0: mBindings->RemoveDependencies(aSubject, aResult); michael@0: }