qdoc: Fixed to report read-only QML properties correctly
authorMartin Smith <martin.smith@nokia.com>
Wed, 11 Apr 2012 10:50:22 +0000 (12:50 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 11 Apr 2012 14:08:09 +0000 (16:08 +0200)
Now the default for a QML property is writable. If qdoc
can't detect the actual read-only status, writable is
assumed. There were some cases where qdoc could not
determine the actual read-only/writable status for a
QML property. In these cases, qdoc reported read-only
because the default was read-only, which was not optimal.

Change-Id: I55aeb2bedcde92a414f4d48a8d995e5e9dbca5da
Reviewed-by: Casper van Donderen <casper.vandonderen@nokia.com>
src/tools/qdoc/cppcodemarker.cpp
src/tools/qdoc/cppcodeparser.cpp
src/tools/qdoc/ditaxmlgenerator.cpp
src/tools/qdoc/generator.cpp
src/tools/qdoc/htmlgenerator.cpp
src/tools/qdoc/node.cpp
src/tools/qdoc/node.h

index aea8ed2..165a235 100644 (file)
@@ -1258,8 +1258,20 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
                 NodeList::ConstIterator c = qcn->childNodes().begin();
                 while (c != qcn->childNodes().end()) {
                     if ((*c)->subType() == Node::QmlPropertyGroup) {
+                        bool attached = false;
                         const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c);
-                        if (pgn->isAttached())
+                        NodeList::ConstIterator C = pgn->childNodes().begin();
+                        while (C != pgn->childNodes().end()) {
+                            if ((*C)->type() == Node::QmlProperty) {
+                                const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*C);
+                                if (pn->isAttached()) {
+                                    attached = true;
+                                    break;
+                                }
+                            }
+                            ++C;
+                        }
+                        if (attached)
                             insert(qmlattachedproperties,*c,style,Okay);
                         else
                             insert(qmlproperties,*c,style,Okay);
index b08c6f9..d0822fe 100644 (file)
@@ -937,7 +937,7 @@ Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
         if (splitQmlPropertyArg(doc,(*arg),type,module,element,property)) {
             QmlClassNode* qmlClass = tree_->findQmlClassNode(module,element);
             if (qmlClass) {
-                qmlPropGroup = new QmlPropGroupNode(qmlClass,property,attached);
+                qmlPropGroup = new QmlPropGroupNode(qmlClass,property); //,attached);
             }
         }
         if (qmlPropGroup) {
@@ -950,7 +950,7 @@ Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
             }
             if (correspondingProperty) {
                 bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*');
-                qmlPropNode->setWritable(writableList || correspondingProperty->isWritable());
+                qmlPropNode->setReadOnly(!(writableList || correspondingProperty->isWritable()));
             }
             ++arg;
             while (arg != args.end()) {
@@ -961,7 +961,7 @@ Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
                                                                        attached);
                     if (correspondingProperty) {
                         bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*');
-                        qmlPropNode->setWritable(writableList || correspondingProperty->isWritable());
+                        qmlPropNode->setReadOnly(!(writableList || correspondingProperty->isWritable()));
                     }
                 }
                 ++arg;
@@ -1117,7 +1117,14 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
         }
         else if (node->type() == Node::Fake && node->subType() == Node::QmlPropertyGroup) {
             QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
-            qpgn->setDefault();
+            NodeList::ConstIterator p = qpgn->childNodes().begin();
+            while (p != qpgn->childNodes().end()) {
+                if ((*p)->type() == Node::QmlProperty) {
+                    QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(*p);
+                    qpn->setDefault();
+                }
+                ++p;
+            }
         }
     }
     else if (command == COMMAND_QMLREADONLY) {
@@ -1127,7 +1134,6 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
         }
         else if (node->type() == Node::Fake && node->subType() == Node::QmlPropertyGroup) {
             QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
-            qpgn->setReadOnly(1);
             NodeList::ConstIterator p = qpgn->childNodes().begin();
             while (p != qpgn->childNodes().end()) {
                 if ((*p)->type() == Node::QmlProperty) {
index 3f1e8c0..88a5888 100644 (file)
@@ -4420,14 +4420,11 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node,
                 writeStartTag(DT_li);
                 writeGuidAttribute((Node*)qpn);
                 QString attr;
-                int ro = qpn->getReadOnly();
-                if (ro < 0) {
-                    if (!qpn->isWritable(tree_))
-                        attr = "read-only";
-                }
-                else if (ro > 0)
+                if (!qpn->isReadOnlySet())
+                    qpn->setReadOnly(!qpn->isWritable(tree_));
+                if (qpn->isReadOnly())
                     attr = "read-only";
-                if (qpgn->isDefault()) {
+                if (qpn->isDefault()) {
                     if (!attr.isEmpty())
                         attr += QLatin1Char(' ');
                     attr += "default";
@@ -4462,13 +4459,11 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node,
             writeStartTag(DT_li);
             writeGuidAttribute((Node*)qpn);
             QString attr;
-            int ro = qpn->getReadOnly();
-            if (ro < 0) {
-                const ClassNode* cn = qpn->declarativeCppNode();
-                if (cn && !qpn->isWritable(tree_))
-                    attr = "read-only";
+            if (!qpn->isReadOnlySet()) {
+                if (qpn->declarativeCppNode())
+                    qpn->setReadOnly(!qpn->isWritable(tree_));
             }
-            else if (ro > 0)
+            if (qpn->isReadOnly())
                 attr = "read-only";
             if (qpn->isDefault()) {
                 if (!attr.isEmpty())
@@ -4495,12 +4490,9 @@ void DitaXmlGenerator::generateDetailedQmlMember(Node* node,
                     writeStartTag(DT_li);
                     writeGuidAttribute((Node*)q);
                     QString attr;
-                    int ro = qpn->getReadOnly();
-                    if (ro < 0) {
-                        if (!qpn->isWritable(tree_))
-                            attr = "read-only";
-                    }
-                    else if (ro > 0)
+                    if (!qpn->isReadOnlySet())
+                        qpn->setReadOnly(!qpn->isWritable(tree_));
+                    if (qpn->isReadOnly())
                         attr = "read-only";
                     if (qpn->isDefault()) {
                         if (!attr.isEmpty())
index 8cda8b7..4258bc6 100644 (file)
@@ -611,6 +611,8 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
                         node->doc().location().warning(
                                     tr("No such enum item '%1' in %2").arg(*a).arg(marker->plainFullName(node)),
                                     details);
+                        if (*a == "Void")
+                            qDebug() << "VOID:" << node->name() << definedItems;
                     }
                     else if (!documentedItems.contains(*a)) {
                         node->doc().location().warning(
index 9434ced..8a54d63 100644 (file)
@@ -4072,16 +4072,11 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
                 out() << "<td class=\"tblQmlPropNode\"><p>";
                 out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
 
-                int ro = qpn->getReadOnly();
-                if (ro < 0) {
-                    if (!qpn->isWritable(tree_)) {
-                        out() << "<span class=\"qmlreadonly\">read-only</span>";
-                    }
-                }
-                else if (ro > 0) {
+                if (!qpn->isReadOnlySet())
+                    qpn->setReadOnly(!qpn->isWritable(tree_));
+                if (qpn->isReadOnly())
                     out() << "<span class=\"qmlreadonly\">read-only</span>";
-                }
-                if (qpgn->isDefault())
+                if (qpn->isDefault())
                     out() << "<span class=\"qmldefault\">default</span>";
                 generateQmlItem(qpn, relative, marker, false);
                 out() << "</p></td></tr>";
@@ -4113,16 +4108,12 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
             out() << "<tr valign=\"top\" class=\"odd\">";
             out() << "<td class=\"tblQmlPropNode\"><p>";
             out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
-            int ro = qpn->getReadOnly();
-            if (ro < 0) {
-                const ClassNode* cn = qpn->declarativeCppNode();
-                if (cn && !qpn->isWritable(tree_)) {
-                    out() << "<span class=\"qmlreadonly\">read-only</span>";
-                }
+            if (!qpn->isReadOnlySet()) {
+                if (qpn->declarativeCppNode())
+                    qpn->setReadOnly(!qpn->isWritable(tree_));
             }
-            else if (ro > 0) {
+            if (qpn->isReadOnly())
                 out() << "<span class=\"qmlreadonly\">read-only</span>";
-            }
             if (qpn->isDefault())
                 out() << "<span class=\"qmldefault\">default</span>";
             generateQmlItem(qpn, relative, marker, false);
@@ -4145,16 +4136,10 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
                     out() << "<tr valign=\"top\" class=\"odd\">";
                     out() << "<td class=\"tblQmlPropNode\"><p>";
                     out() << "<a name=\"" + refForNode(q) + "\"></a>";
-
-                    int ro = qpn->getReadOnly();
-                    if (ro < 0) {
-                        if (!qpn->isWritable(tree_)) {
-                            out() << "<span class=\"qmlreadonly\">read-only</span>";
-                        }
-                    }
-                    else if (ro > 0) {
+                    if (!qpn->isReadOnlySet())
+                        qpn->setReadOnly(!qpn->isWritable(tree_));
+                    if (qpn->isReadOnly())
                         out() << "<span class=\"qmlreadonly\">read-only</span>";
-                    }
                     if (qpn->isDefault())
                         out() << "<span class=\"qmldefault\">default</span>";
                     generateQmlItem(q, relative, marker, false);
index 703c073..1ee4719 100644 (file)
@@ -327,6 +327,38 @@ void Node::setPageType(const QString& t)
         pageType_ = DitaMapPage;
 }
 
+/*! Converts the boolean value \a b to an enum representation
+  of the boolean type, which includes an enum value for the
+  \e {default value} of the item, i.e. true, false, or default.
+ */
+Node::FlagValue Node::toFlagValue(bool b)
+{
+    return b ? FlagValueTrue : FlagValueFalse;
+}
+
+/*!
+  Converts the enum \a fv back to a boolean value.
+  If \a fv is neither the true enum value nor the
+  false enum value, the boolean value returned is
+  \a defaultValue.
+
+  Note that runtimeDesignabilityFunction() should be called
+  first. If that function returns the name of a function, it
+  means the function must be called at runtime to determine
+  whether the property is Designable.
+ */
+bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
+{
+    switch (fv) {
+    case FlagValueTrue:
+        return true;
+    case FlagValueFalse:
+        return false;
+    default:
+        return defaultValue;
+    }
+}
+
 /*!
   Sets the pointer to the node that this node relates to.
  */
@@ -1876,11 +1908,11 @@ void FunctionNode::debug() const
  */
 PropertyNode::PropertyNode(InnerNode *parent, const QString& name)
     : LeafNode(Property, parent, name),
-      sto(Trool_Default),
-      des(Trool_Default),
-      scr(Trool_Default),
-      wri(Trool_Default),
-      usr(Trool_Default),
+      stored_(FlagValueDefault),
+      designable_(FlagValueDefault),
+      scriptable_(FlagValueDefault),
+      writable_(FlagValueDefault),
+      user_(FlagValueDefault),
       cst(false),
       fnl(false),
       rev(-1),
@@ -1905,16 +1937,16 @@ void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
         if (funcs[i].isEmpty())
             funcs[i] = baseProperty->funcs[i];
     }
-    if (sto == Trool_Default)
-        sto = baseProperty->sto;
-    if (des == Trool_Default)
-        des = baseProperty->des;
-    if (scr == Trool_Default)
-        scr = baseProperty->scr;
-    if (wri == Trool_Default)
-        wri = baseProperty->wri;
-    if (usr == Trool_Default)
-        usr = baseProperty->usr;
+    if (stored_ == FlagValueDefault)
+        stored_ = baseProperty->stored_;
+    if (designable_ == FlagValueDefault)
+        designable_ = baseProperty->designable_;
+    if (scriptable_ == FlagValueDefault)
+        scriptable_ = baseProperty->scriptable_;
+    if (writable_ == FlagValueDefault)
+        writable_ = baseProperty->writable_;
+    if (user_ == FlagValueDefault)
+        user_ = baseProperty->user_;
     overrides = baseProperty;
 }
 
@@ -1940,38 +1972,6 @@ QString PropertyNode::qualifiedDataType() const
     }
 }
 
-/*! Converts the \a boolean value to an enum representation
-  of the boolean type, which includes an enum  value for the
-  \e {default value} of the item, i.e. true, false, or default.
- */
-PropertyNode::Trool PropertyNode::toTrool(bool boolean)
-{
-    return boolean ? Trool_True : Trool_False;
-}
-
-/*!
-  Converts the enum \a troolean back to a boolean value.
-  If \a troolean is neither the true enum value nor the
-  false enum value, the boolean value returned is
-  \a defaultValue.
-
-  Note that runtimeDesignabilityFunction() should be called
-  first. If that function returns the name of a function, it
-  means the function must be called at runtime to determine
-  whether the property is Designable.
- */
-bool PropertyNode::fromTrool(Trool troolean, bool defaultValue)
-{
-    switch (troolean) {
-    case Trool_True:
-        return true;
-    case Trool_False:
-        return false;
-    default:
-        return defaultValue;
-    }
-}
-
 bool QmlClassNode::qmlOnly = false;
 QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
 QMap<QString, QmlClassNode*> QmlClassNode::moduleMap;
@@ -2181,13 +2181,14 @@ QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
   Constructor for the Qml property group node. \a parent is
   always a QmlClassNode.
  */
-QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent,
-                                   const QString& name,
-                                   bool attached)
-    : FakeNode(parent, name, QmlPropertyGroup, Node::ApiPage),
+QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name)
+    //bool attached)
+    : FakeNode(parent, name, QmlPropertyGroup, Node::ApiPage)
+#if 0
       isdefault_(false),
       attached_(attached),
       readOnly_(-1)
+#endif
 {
     // nothing.
 }
@@ -2207,11 +2208,11 @@ QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
                                  bool attached)
     : LeafNode(QmlProperty, parent, name),
       type_(type),
-      sto(Trool_Default),
-      des(Trool_Default),
+      stored_(FlagValueDefault),
+      designable_(FlagValueDefault),
       isdefault_(false),
       attached_(attached),
-      readOnly_(-1)
+      readOnly_(FlagValueDefault)
 {
     setPageType(ApiPage);
 }
@@ -2226,11 +2227,11 @@ QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent,
                                  bool attached)
     : LeafNode(QmlProperty, parent, name),
       type_(type),
-      sto(Trool_Default),
-      des(Trool_Default),
+      stored_(FlagValueDefault),
+      designable_(FlagValueDefault),
       isdefault_(false),
       attached_(attached),
-      readOnly_(-1)
+      readOnly_(FlagValueDefault)
 {
     setPageType(ApiPage);
 }
@@ -2252,39 +2253,16 @@ QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent,
                                  bool attached)
     : LeafNode(parent->parent(), QmlProperty, name),
       type_(type),
-      sto(Trool_Default),
-      des(Trool_Default),
+      stored_(FlagValueDefault),
+      designable_(FlagValueDefault),
       isdefault_(false),
       attached_(attached),
-      readOnly_(-1)
+      readOnly_(FlagValueDefault)
 {
     setPageType(ApiPage);
 }
 
 /*!
-  I don't know what this is.
- */
-QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean)
-{
-    return boolean ? Trool_True : Trool_False;
-}
-
-/*!
-  I don't know what this is either.
- */
-bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
-{
-    switch (troolean) {
-    case Trool_True:
-        return true;
-    case Trool_False:
-        return false;
-    default:
-        return defaultValue;
-    }
-}
-
-/*!
   Returns true if a QML property or attached property is
   read-only. The algorithm for figuring this out is long
   amd tedious and almost certainly will break. It currently
@@ -2293,14 +2271,16 @@ bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
  */
 bool QmlPropertyNode::isWritable(Tree* tree)
 {
-    if (wri != Trool_Default)
-        return fromTrool(wri, false);
+    if (readOnly_ != FlagValueDefault) {
+        return !fromFlagValue(readOnly_, false);
+    }
 
     PropertyNode* pn = correspondingProperty(tree);
-    if (pn)
+    if (pn) {
         return pn->isWritable();
+    }
     else {
-        location().warning(tr("Can't determine read-only status of QML property %1; writable assumed.").arg(name()));
+        location().warning(tr("Can't detect if QML property %1 isread-only; writable assumed.").arg(name()));
         return true;
     }
 }
index cfd446d..45b5ded 100644 (file)
@@ -156,6 +156,12 @@ public:
         OnBeyondZebra
     };
 
+    enum FlagValue {
+        FlagValueDefault = -1,
+        FlagValueFalse = 0,
+        FlagValueTrue = 1
+    };
+
     virtual ~Node();
 
     void setAccess(Access access) { access_ = access; }
@@ -239,6 +245,9 @@ public:
     static QString cleanId(QString str);
     QString idForNode() const;
 
+    static FlagValue toFlagValue(bool b);
+    static bool fromFlagValue(FlagValue fv, bool defaultValue);
+
     static QString pageTypeString(unsigned t);
     static QString nodeTypeString(unsigned t);
     static QString nodeSubtypeString(unsigned t);
@@ -553,9 +562,8 @@ public:
 class QmlPropGroupNode : public FakeNode
 {
 public:
-    QmlPropGroupNode(QmlClassNode* parent,
-                     const QString& name,
-                     bool attached);
+    QmlPropGroupNode(QmlClassNode* parent, const QString& name);
+    //bool attached);
     virtual ~QmlPropGroupNode() { }
     virtual bool isQmlNode() const { return true; }
     virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); }
@@ -564,6 +572,7 @@ public:
     virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
 
     const QString& element() const { return parent()->name(); }
+#if 0
     void setDefault() { isdefault_ = true; }
     void setReadOnly(int ro) { readOnly_ = ro; }
     int getReadOnly() const { return readOnly_; }
@@ -575,6 +584,7 @@ private:
     bool    isdefault_;
     bool    attached_;
     int     readOnly_;
+#endif
 };
 
 class QmlPropertyNode;
@@ -597,21 +607,20 @@ public:
     virtual ~QmlPropertyNode() { }
 
     void setDataType(const QString& dataType) { type_ = dataType; }
-    void setStored(bool stored) { sto = toTrool(stored); }
-    void setDesignable(bool designable) { des = toTrool(designable); }
-    void setWritable(bool writable) { wri = toTrool(writable); }
+    void setStored(bool stored) { stored_ = toFlagValue(stored); }
+    void setDesignable(bool designable) { designable_ = toFlagValue(designable); }
+    void setReadOnly(bool ro) { readOnly_ = toFlagValue(ro); }
+    void setDefault() { isdefault_ = true; }
 
     const QString &dataType() const { return type_; }
     QString qualifiedDataType() const { return type_; }
-    void setDefault() { isdefault_ = true; }
-    void setReadOnly(int ro) { readOnly_ = ro; }
-    int getReadOnly() const { return readOnly_; }
+    bool isReadOnlySet() const { return (readOnly_ != FlagValueDefault); }
     bool isDefault() const { return isdefault_; }
-    bool isStored() const { return fromTrool(sto,true); }
-    bool isDesignable() const { return fromTrool(des,false); }
+    bool isStored() const { return fromFlagValue(stored_,true); }
+    bool isDesignable() const { return fromFlagValue(designable_,false); }
     bool isWritable(Tree* tree);
     bool isAttached() const { return attached_; }
-    bool isReadOnly() const { return (readOnly_ > 0); }
+    bool isReadOnly() const { return fromFlagValue(readOnly_,false); }
     virtual bool isQmlNode() const { return true; }
     virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); }
     virtual QString qmlModuleName() const { return parent()->qmlModuleName(); }
@@ -625,18 +634,12 @@ public:
     const NodeList& qmlPropNodes() const { return qmlPropNodes_; }
 
 private:
-    enum Trool { Trool_True, Trool_False, Trool_Default };
-
-    static Trool toTrool(bool boolean);
-    static bool fromTrool(Trool troolean, bool defaultValue);
-
     QString type_;
-    Trool   sto;
-    Trool   des;
-    Trool   wri;
+    FlagValue   stored_;
+    FlagValue   designable_;
     bool    isdefault_;
     bool    attached_;
-    int     readOnly_;
+    FlagValue   readOnly_;
     NodeList qmlPropNodes_;
 };
 
@@ -842,11 +845,11 @@ public:
     void setDataType(const QString& dataType) { type_ = dataType; }
     void addFunction(FunctionNode* function, FunctionRole role);
     void addSignal(FunctionNode* function, FunctionRole role);
-    void setStored(bool stored) { sto = toTrool(stored); }
-    void setDesignable(bool designable) { des = toTrool(designable); }
-    void setScriptable(bool scriptable) { scr = toTrool(scriptable); }
-    void setWritable(bool writable) { wri = toTrool(writable); }
-    void setUser(bool user) { usr = toTrool(user); }
+    void setStored(bool stored) { stored_ = toFlagValue(stored); }
+    void setDesignable(bool designable) { designable_ = toFlagValue(designable); }
+    void setScriptable(bool scriptable) { scriptable_ = toFlagValue(scriptable); }
+    void setWritable(bool writable) { writable_ = toFlagValue(writable); }
+    void setUser(bool user) { user_ = toFlagValue(user); }
     void setOverriddenFrom(const PropertyNode* baseProperty);
     void setRuntimeDesFunc(const QString& rdf) { runtimeDesFunc = rdf; }
     void setRuntimeScrFunc(const QString& scrf) { runtimeScrFunc = scrf; }
@@ -862,13 +865,13 @@ public:
     NodeList setters() const { return functions(Setter); }
     NodeList resetters() const { return functions(Resetter); }
     NodeList notifiers() const { return functions(Notifier); }
-    bool isStored() const { return fromTrool(sto, storedDefault()); }
-    bool isDesignable() const { return fromTrool(des, designableDefault()); }
-    bool isScriptable() const { return fromTrool(scr, scriptableDefault()); }
+    bool isStored() const { return fromFlagValue(stored_, storedDefault()); }
+    bool isDesignable() const { return fromFlagValue(designable_, designableDefault()); }
+    bool isScriptable() const { return fromFlagValue(scriptable_, scriptableDefault()); }
     const QString& runtimeDesignabilityFunction() const { return runtimeDesFunc; }
     const QString& runtimeScriptabilityFunction() const { return runtimeScrFunc; }
-    bool isWritable() const { return fromTrool(wri, writableDefault()); }
-    bool isUser() const { return fromTrool(usr, userDefault()); }
+    bool isWritable() const { return fromFlagValue(writable_, writableDefault()); }
+    bool isUser() const { return fromFlagValue(user_, userDefault()); }
     bool isConstant() const { return cst; }
     bool isFinal() const { return fnl; }
     const PropertyNode* overriddenFrom() const { return overrides; }
@@ -880,20 +883,15 @@ public:
     bool writableDefault() const { return !setters().isEmpty(); }
 
 private:
-    enum Trool { Trool_True, Trool_False, Trool_Default };
-
-    static Trool toTrool(bool boolean);
-    static bool fromTrool(Trool troolean, bool defaultValue);
-
     QString type_;
     QString runtimeDesFunc;
     QString runtimeScrFunc;
     NodeList funcs[NumFunctionRoles];
-    Trool sto;
-    Trool des;
-    Trool scr;
-    Trool wri;
-    Trool usr;
+    FlagValue stored_;
+    FlagValue designable_;
+    FlagValue scriptable_;
+    FlagValue writable_;
+    FlagValue user_;
     bool cst;
     bool fnl;
     int rev;