• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 * SynchedPropertyObjectTwoWayPU
18 * implementation of @Link and @Consume decorated variables of type class object
19 *
20 * all definitions in this file are framework internal
21*/
22
23class SynchedPropertyTwoWayPU<C> extends ObservedPropertyAbstractPU<C>
24  implements PeerChangeEventReceiverPU<C>, ObservedObjectEventsPUReceiver<C> {
25
26  private source_: ObservedPropertyObjectAbstract<C>;
27  private changeNotificationIsOngoing_: boolean = false;
28
29  constructor(source: ObservedPropertyObjectAbstract<C>,
30    owningChildView: IPropertySubscriber,
31    thisPropertyName: PropertyInfo) {
32    super(owningChildView, thisPropertyName);
33    this.source_ = source;
34    if (this.source_) {
35      // register to the parent property
36      this.source_.addSubscriber(this);
37    } else {
38      throw new SyntaxError(`${this.debugInfo()}: constructor: source variable in parent/ancestor @Component must be defined. Application error!`);
39    }
40  }
41
42  /*
43  like a destructor, need to call this before deleting
44  the property.
45  */
46  aboutToBeDeleted() {
47    // unregister from parent of this link
48    if (this.source_) {
49      this.source_.removeSubscriber(this);
50
51        // unregister from the ObservedObject
52        ObservedObject.removeOwningProperty(this.source_.getUnmonitored(), this);
53    }
54    super.aboutToBeDeleted();
55  }
56
57  public debugInfoDecorator() : string {
58    return `@Link/@Consume (class SynchedPropertyTwoWayPU)`;
59  }
60
61  private isStorageLinkProp() : boolean {
62    return  (this.source_ && this.source_ instanceof ObservedPropertyAbstract && (!(this.source_ instanceof ObservedPropertyAbstractPU)));
63  }
64
65  private setObject(newValue: C): void {
66    if (!this.source_) {
67      throw new SyntaxError(`${this.debugInfo()}: setObject (assign a new value), no source variable in parent/ancestor \
68                                                    @Component. Application error.`);
69
70    }
71
72    if (this.getUnmonitored() === newValue) {
73      stateMgmtConsole.debug(`SynchedPropertyObjectTwoWayPU[${this.id__()}IP, '${this.info() || "unknown"}']: set with unchanged value - ignoring.`);
74      return;
75    }
76
77    stateMgmtConsole.propertyAccess(`${this.debugInfo()}: set: value has changed.`);
78
79    if (this.checkIsSupportedValue(newValue)) {
80    // the source_ ObservedProperty will call: this.syncPeerHasChanged(newValue);
81    this.source_.set(newValue)
82    }
83  }
84
85
86  /**
87   * Called when sync peer ObservedPropertyObject or SynchedPropertyObjectTwoWay has changed value
88   * that peer can be in either parent or child component if 'this' is used for a @Link
89   * that peer can be in either ancestor or descendant component if 'this' is used for a @Consume
90   * @param eventSource
91   */
92  syncPeerHasChanged(eventSource: ObservedPropertyAbstractPU<C>) {
93    if (!this.changeNotificationIsOngoing_) {
94      stateMgmtConsole.debug(`${this.debugInfo()}: syncPeerHasChanged: from peer '${eventSource && eventSource.debugInfo && eventSource.debugInfo()}' .`)
95      this.notifyPropertyHasChangedPU();
96    }
97  }
98
99  /**
100   * called when wrapped ObservedObject has changed poperty
101   * @param souceObject
102   * @param changedPropertyName
103   */
104  public objectPropertyHasChangedPU(sourceObject: ObservedObject<C>, changedPropertyName : string) {
105    stateMgmtConsole.debug(`${this.debugInfo()}: objectPropertyHasChangedPU: property '${changedPropertyName}' of \
106    object value has changed.`)
107
108    this.notifyPropertyHasChangedPU();
109  }
110
111  public objectPropertyHasBeenReadPU(sourceObject: ObservedObject<C>, changedPropertyName : string) {
112    stateMgmtConsole.debug(`${this.debugInfo()}: objectPropertyHasBeenReadPU: property '${changedPropertyName}' of object value has been read.`);
113    this.notifyPropertyHasBeenReadPU();
114  }
115
116  public getUnmonitored(): C {
117    stateMgmtConsole.propertyAccess(`${this.debugInfo()}: getUnmonitored.`);
118    // unmonitored get access , no call to otifyPropertyRead !
119    return (this.source_ ? this.source_.getUnmonitored() : undefined);
120  }
121
122  // get 'read through` from the ObservedProperty
123  public get(): C {
124    stateMgmtConsole.propertyAccess(`${this.debugInfo()}: get`)
125    this.notifyPropertyHasBeenReadPU()
126    return this.getUnmonitored();
127  }
128
129  // set 'writes through` to the ObservedProperty
130  public set(newValue: C): void {
131    if (this.getUnmonitored() === newValue) {
132      stateMgmtConsole.debug(`SynchedPropertyObjectTwoWayPU[${this.id__()}IP, '${this.info() || "unknown"}']: set with unchanged value  - nothing to do.`);
133      return;
134    }
135
136    stateMgmtConsole.propertyAccess(`${this.debugInfo()}: set: value about to change.`);
137
138    // avoid circular notifications @Link -> source @State -> other but also back to same @Link
139    this.changeNotificationIsOngoing_ = true;
140    this.setObject(newValue);
141    this.notifyPropertyHasChangedPU();
142    this.changeNotificationIsOngoing_ = false;
143  }
144}
145
146// class definitions for backward compatibility
147class SynchedPropertyObjectTwoWayPU<C> extends SynchedPropertyTwoWayPU<C> {
148
149}
150
151class SynchedPropertySimpleTwoWayPU<T> extends SynchedPropertyTwoWayPU<T> {
152
153}
154
155