1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.eclipse.org/org/documents/epl-v10.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.ide.eclipse.adt.internal.editors.uimodel;
18
19import com.android.ide.common.xml.XmlAttributeSortOrder;
20import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
21import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
22
23import org.eclipse.swt.widgets.Composite;
24import org.eclipse.ui.forms.IManagedForm;
25import org.w3c.dom.Node;
26
27/**
28 * Represents an XML attribute that can be modified by the XML editor's user interface.
29 * <p/>
30 * The characteristics of an {@link UiAttributeNode} are declared by a
31 * corresponding {@link AttributeDescriptor}.
32 * <p/>
33 * This is an abstract class. Derived classes must implement the creation of the UI
34 * and manage its synchronization with the XML.
35 */
36public abstract class UiAttributeNode implements Comparable<UiAttributeNode> {
37
38    private AttributeDescriptor mDescriptor;
39    private UiElementNode mUiParent;
40    private boolean mIsDirty;
41    private boolean mHasError;
42
43    /** Creates a new {@link UiAttributeNode} linked to a specific {@link AttributeDescriptor}
44     * and the corresponding runtime {@link UiElementNode} parent. */
45    public UiAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) {
46        mDescriptor = attributeDescriptor;
47        mUiParent = uiParent;
48    }
49
50    /** Returns the {@link AttributeDescriptor} specific to this UI attribute node */
51    public final AttributeDescriptor getDescriptor() {
52        return mDescriptor;
53    }
54
55    /** Returns the {@link UiElementNode} that owns this {@link UiAttributeNode} */
56    public final UiElementNode getUiParent() {
57        return mUiParent;
58    }
59
60    /** Returns the current value of the node. */
61    public abstract String getCurrentValue();
62
63    /**
64     * @return True if the attribute has been changed since it was last loaded
65     *         from the XML model.
66     */
67    public final boolean isDirty() {
68        return mIsDirty;
69    }
70
71    /**
72     * Sets whether the attribute is dirty and also notifies the editor some part's dirty
73     * flag as changed.
74     * <p/>
75     * Subclasses should set the to true as a result of user interaction with the widgets in
76     * the section and then should set to false when the commit() method completed.
77     *
78     * @param isDirty the new value to set the dirty-flag to
79     */
80    public void setDirty(boolean isDirty) {
81        boolean wasDirty = mIsDirty;
82        mIsDirty = isDirty;
83        // TODO: for unknown attributes, getParent() != null && getParent().getEditor() != null
84        if (wasDirty != isDirty) {
85            AndroidXmlEditor editor = getUiParent().getEditor();
86            if (editor != null) {
87                editor.editorDirtyStateChanged();
88            }
89        }
90    }
91
92    /**
93     * Sets the error flag value.
94     * @param errorFlag the error flag
95     */
96    public final void setHasError(boolean errorFlag) {
97        mHasError = errorFlag;
98    }
99
100    /**
101     * Returns whether this node has errors.
102     */
103    public final boolean hasError() {
104        return mHasError;
105    }
106
107    /**
108     * Called once by the parent user interface to creates the necessary
109     * user interface to edit this attribute.
110     * <p/>
111     * This method can be called more than once in the life cycle of an UI node,
112     * typically when the UI is part of a master-detail tree, as pages are swapped.
113     *
114     * @param parent The composite where to create the user interface.
115     * @param managedForm The managed form owning this part.
116     */
117    public abstract void createUiControl(Composite parent, IManagedForm managedForm);
118
119    /**
120     * Used to get a list of all possible values for this UI attribute.
121     * <p/>
122     * This is used, among other things, by the XML Content Assists to complete values
123     * for an attribute.
124     * <p/>
125     * Implementations that do not have any known values should return null.
126     *
127     * @param prefix An optional prefix string, which is whatever the user has already started
128     *   typing. Can be null or an empty string. The implementation can use this to filter choices
129     *   and only return strings that match this prefix. A lazy or default implementation can
130     *   simply ignore this and return everything.
131     * @return A list of possible completion values, and empty array or null.
132     */
133    public abstract String[] getPossibleValues(String prefix);
134
135    /**
136     * Called when the XML is being loaded or has changed to
137     * update the value held by this user interface attribute node.
138     * <p/>
139     * The XML Node <em>may</em> be null, which denotes that the attribute is not
140     * specified in the XML model. In general, this means the "default" value of the
141     * attribute should be used.
142     * <p/>
143     * The caller doesn't really know if attributes have changed,
144     * so it will call this to refresh the attribute anyway. It's up to the
145     * UI implementation to minimize refreshes.
146     *
147     * @param node the node to read the value from
148     */
149    public abstract void updateValue(Node node);
150
151    /**
152     * Called by the user interface when the editor is saved or its state changed
153     * and the modified attributes must be committed (i.e. written) to the XML model.
154     * <p/>
155     * Important behaviors:
156     * <ul>
157     * <li>The caller *must* have called IStructuredModel.aboutToChangeModel before.
158     *     The implemented methods must assume it is safe to modify the XML model.
159     * <li>On success, the implementation *must* call setDirty(false).
160     * <li>On failure, the implementation can fail with an exception, which
161     *     is trapped and logged by the caller, or do nothing, whichever is more
162     *     appropriate.
163     * </ul>
164     */
165    public abstract void commit();
166
167    // ---- Implements Comparable ----
168
169    @Override
170    public int compareTo(UiAttributeNode o) {
171        return XmlAttributeSortOrder.compareAttributes(mDescriptor.getXmlLocalName(),
172                o.mDescriptor.getXmlLocalName());
173    }
174}
175