1/* 2 * Copyright (c) 2021-2022 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 * ObservedPropertyObject 18 * 19 * all definitions in this file are framework internal 20 * 21 * class that holds an actual property value of type T 22 * uses its base class to manage subscribers to this 23 * property. 24*/ 25class ObservedPropertyObject<T extends Object> extends ObservedPropertyObjectAbstract<T> 26 implements ISinglePropertyChangeSubscriber<T> { 27 28 private wrappedValue_: T; 29 30 constructor(value: T, owningView: IPropertySubscriber, propertyName: PropertyInfo) { 31 super(owningView, propertyName); 32 this.setValueInternal(value); 33 } 34 35 aboutToBeDeleted(unsubscribeMe?: IPropertySubscriber) { 36 this.unsubscribeFromOwningProperty(); 37 if (unsubscribeMe) { 38 this.unlinkSuscriber(unsubscribeMe.id__()); 39 } 40 super.aboutToBeDeleted(); 41 } 42 43 // notification from ObservedObject value one of its 44 // props has chnaged. Implies the ObservedProperty has changed 45 // Note: this function gets called when in this case: 46 // thisProp.aObsObj.aProp = 47 a object prop gets changed 47 // It is NOT called when 48 // thisProp.aObsObj = new ClassA 49 hasChanged(newValue: T): void { 50 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: hasChanged`); 51 this.notifyHasChanged(this.wrappedValue_); 52 } 53 54 private unsubscribeFromOwningProperty() { 55 if (this.wrappedValue_) { 56 if (this.wrappedValue_ instanceof SubscribaleAbstract) { 57 (this.wrappedValue_ as SubscribaleAbstract).removeOwningProperty(this); 58 } else { 59 ObservedObject.removeOwningProperty(this.wrappedValue_, this); 60 } 61 } 62 } 63 /* 64 actually update this.wrappedValue_ 65 called needs to do value change check 66 and also notify with this.aboutToChange(); 67 */ 68 private setValueInternal(newValue: T): boolean { 69 if (typeof newValue !== 'object') { 70 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is NOT an object. Application error. Ignoring set.`); 71 return false; 72 } 73 74 this.unsubscribeFromOwningProperty(); 75 76 if (ObservedObject.IsObservedObject(newValue)) { 77 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an ObservedObject already`); 78 ObservedObject.addOwningProperty(newValue, this); 79 this.wrappedValue_ = newValue; 80 } else if (newValue instanceof SubscribaleAbstract) { 81 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an SubscribaleAbstract, subscribiung to it.`); 82 this.wrappedValue_ = newValue; 83 (this.wrappedValue_ as unknown as SubscribaleAbstract).addOwningProperty(this); 84 } else { 85 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an Object, needs to be wrapped in an ObservedObject.`); 86 this.wrappedValue_ = ObservedObject.createNew(newValue, this); 87 } 88 return true; 89 } 90 91 public get(): T { 92 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: get`); 93 this.notifyPropertyRead(); 94 return this.wrappedValue_; 95 } 96 97 public set(newValue: T): void { 98 if (this.wrappedValue_ == newValue) { 99 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: set with unchanged value - ignoring.`); 100 return; 101 } 102 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: set, changed`); 103 this.setValueInternal(newValue); 104 this.notifyHasChanged(newValue); 105 } 106 107/** 108 * These functions are used 109 * LocalStorage.link (also in partial update config) 110 * (FU)View.initializeConsumeinitializeConsume 111 */ 112 public createLink(subscribeOwner?: IPropertySubscriber, 113 linkPropName?: PropertyInfo): ObservedPropertyAbstract<T> { 114 return new SynchedPropertyObjectTwoWay(this, subscribeOwner, linkPropName); 115 } 116 117 public createProp(subscribeOwner?: IPropertySubscriber, 118 linkPropName?: PropertyInfo): ObservedPropertyAbstract<T> { 119 throw new Error("Creating a 'Prop' property is unsupported for Object type property value."); 120 } 121} 122