1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16/* 17 class that holds an actual property value of type T 18 uses its base class to manage subscribers to this 19 property. 20*/ 21class ObservedPropertyObject<T extends Object> extends ObservedPropertyObjectAbstract<T> 22 implements ISinglePropertyChangeSubscriber<T> { 23 24 private wrappedValue_: T; 25 26 constructor(value: T, owningView: IPropertySubscriber, propertyName: PropertyInfo) { 27 super(owningView, propertyName); 28 this.setValueInternal(value); 29 } 30 31 aboutToBeDeleted(unsubscribeMe?: IPropertySubscriber) { 32 this.unsubscribeFromOwningProperty(); 33 if (unsubscribeMe) { 34 this.unlinkSuscriber(unsubscribeMe.id__()); 35 } 36 super.aboutToBeDeleted(); 37 } 38 39 // FIXME 40 // notification from ObservedObject value one of its 41 // props has chnaged. Implies the ObservedProperty has changed 42 // Note: this function gets called when in this case: 43 // thisProp.aObsObj.aProp = 47 a object prop gets changed 44 // It is NOT called when 45 // thisProp.aObsObj = new ClassA 46 hasChanged(newValue: T): void { 47 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: hasChanged`); 48 this.notifyHasChanged(this.wrappedValue_); 49 } 50 51 private unsubscribeFromOwningProperty() { 52 if (this.wrappedValue_) { 53 if (this.wrappedValue_ instanceof SubscribaleAbstract) { 54 (this.wrappedValue_ as SubscribaleAbstract).removeOwningProperty(this); 55 } else { 56 ObservedObject.removeOwningProperty(this.wrappedValue_, this); 57 } 58 } 59 } 60 /* 61 actually update this.wrappedValue_ 62 called needs to do value change check 63 and also notify with this.aboutToChange(); 64 */ 65 private setValueInternal(newValue: T): boolean { 66 if (typeof newValue !== 'object') { 67 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is NOT an object. Application error. Ignoring set.`); 68 return false; 69 } 70 71 this.unsubscribeFromOwningProperty(); 72 73 if (ObservedObject.IsObservedObject(newValue)) { 74 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an ObservedObject already`); 75 ObservedObject.addOwningProperty(newValue, this); 76 this.wrappedValue_ = newValue; 77 } else if (newValue instanceof SubscribaleAbstract) { 78 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an SubscribaleAbstract, subscribiung to it.`); 79 this.wrappedValue_ = newValue; 80 (this.wrappedValue_ as unknown as SubscribaleAbstract).addOwningProperty(this); 81 } else { 82 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an Object, needs to be wrapped in an ObservedObject.`); 83 this.wrappedValue_ = ObservedObject.createNew(newValue, this); 84 } 85 return true; 86 } 87 88 public get(): T { 89 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: get`); 90 this.notifyPropertyRead(); 91 return this.wrappedValue_; 92 } 93 94 public set(newValue: T): void { 95 if (this.wrappedValue_ == newValue) { 96 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: set with unchanged value - ignoring.`); 97 return; 98 } 99 console.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: set, changed`); 100 this.setValueInternal(newValue); 101 this.notifyHasChanged(newValue); 102 } 103 104 /** 105 * These functions are meant for use in connection with the App Stoage and 106 * business logic implementation. 107 * the created Link and Prop will update when 'this' property value 108 * changes. 109 */ 110 public createLink(subscribeOwner?: IPropertySubscriber, 111 linkPropName?: PropertyInfo, contentObserver?: ObservedPropertyAbstract<T>): ObservedPropertyAbstract<T> { 112 return new SynchedPropertyObjectTwoWay(this, subscribeOwner, linkPropName, contentObserver); 113 } 114 115 public createProp(subscribeOwner?: IPropertySubscriber, 116 linkPropName?: PropertyInfo, contentObserver?: ObservedPropertyAbstract<T>): ObservedPropertyAbstract<T> { 117 throw new Error("Creating a 'Prop' proerty is unsuppoeted for Object type prperty value."); 118 } 119} 120