Fix T39080: copy-to-selected operator fails for pointer properties.
authorLukas Tönne <lukas.toenne@gmail.com>
Tue, 11 Mar 2014 13:57:11 +0000 (14:57 +0100)
committerLukas Tönne <lukas.toenne@gmail.com>
Tue, 11 Mar 2014 13:58:53 +0000 (14:58 +0100)
The copy-to-selected operator for RNA buttons uses paths for copying
object pointer properties. Copying other ID data blocks is deliberately
disabled:
https://developer.blender.org/diffusion/B/browse/master/source/blender/editors/interface/interface_ops.c$274

However, the RNA_path_resolve_full function is not properly working for
retrieving pointer properties: it always will dereference pointer
properties in anticipation of further path elements.

In fact the return value of RNA_path_resolve_full has a conflicting
double meaning. It returns `false` when
* the RNA path is invalid
* any of the pointer properties is NULL

This means that it is not capable of returning pointer properties at all.
To make this possible, there is now an internal function for path
parsing, which returns false //only// if the the path is invalid.
On top of this there are 4 wrapper functions for retrieving either
actual property values (RNA_path_resolve, RNA_path_resolve_full) and for
retrieving pointer+property pairs (RNA_path_resolve_property,
RNA_path_resolve_property_full). The latter 2 variants will **not**
dereference pointer properties at the end of the path, so callers can
actually get the property itself. The `***_full` variants include an
array index return value.

Differential Revision: https://developer.blender.org/D396

source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_access.c

index ed33098858fe029e93a226d64d9ee222b1bb08ab..f385d61601a33a069517a1ba21c53f62d769177f 100644 (file)
@@ -914,14 +914,14 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path,
                      PointerRNA *r_ptr, PropertyRNA **r_prop);
 
 bool RNA_path_resolve_full(PointerRNA *ptr, const char *path,
-                          PointerRNA *r_ptr, PropertyRNA **r_prop, int *index);
+                           PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
 
 /* path_resolve_property() variants ensure that pointer + property both exist */
 bool RNA_path_resolve_property(PointerRNA *ptr, const char *path,
-                     PointerRNA *r_ptr, PropertyRNA **r_prop);
+                               PointerRNA *r_ptr, PropertyRNA **r_prop);
 
 bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path,
-                          PointerRNA *r_ptr, PropertyRNA **r_prop, int *index);
+                                    PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
 
 char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
 char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
index 7138f97bf9a931ef2bff754322ef387921d123a3..51e01d937999ac51fed98a212bb64a971f083893 100644 (file)
@@ -3873,40 +3873,13 @@ static int rna_token_strip_quotes(char *token)
        return 0;
 }
 
-/* Resolve the given RNA Path to find both the pointer AND property indicated by fully resolving the path
- * ! This is a convenience method to avoid logic errors and ugly syntax
- * ! Assumes all pointers provided are valid
- * > returns: True only if both a valid pointer and property are found after resolving the path 
- */
-bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
-{
-       return RNA_path_resolve_full(ptr, path, r_ptr, r_prop, NULL) && (*r_prop != NULL);
-}
-
-/* Resolve the given RNA Path to find the pointer AND property (as well as the array index) indicated by fully resolving the path
- * ! This is a convenience method to avoid logic errors and ugly syntax
- * ! Assumes all pointers provided are valid
- * > returns: True only if both a valid pointer and property are found after resolving the path
- */
-bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *index)
-{
-       return RNA_path_resolve_full(ptr, path, r_ptr, r_prop, index) && (*r_prop != NULL);
-}
-
-/* Resolve the given RNA Path to find the pointer and/or property indicated by fully resolving the path 
- * ! Assumes all pointers provided are valid
- * > returns: True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
-bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
-{
-       return RNA_path_resolve_full(ptr, path, r_ptr, r_prop, NULL);
-}
-
-static bool rna_path_resolve_collection_key(const char **path, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_nextptr)
+static bool rna_path_parse_collection_key(const char **path, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_nextptr)
 {
        char fixedbuf[256], *token;
        int intkey;
        
+       *r_nextptr = *ptr;
+
        /* end of path, ok */
        if (!(**path))
                return true;
@@ -3955,10 +3928,10 @@ static bool rna_path_resolve_collection_key(const char **path, PointerRNA *ptr,
                }
        }
        
-       return r_nextptr->data != NULL;
+       return true;
 }
 
-static bool rna_path_resolve_array_index(const char **path, PointerRNA *ptr, PropertyRNA *prop, int *r_index)
+static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, PropertyRNA *prop, int *r_index)
 {
        char fixedbuf[256], *token;
        int index_arr[RNA_MAX_ARRAY_DIMENSION] = {0};
@@ -4041,15 +4014,12 @@ static bool rna_path_resolve_array_index(const char **path, PointerRNA *ptr, Pro
        return true;
 }
 
-/* Resolve the given RNA Path to find the pointer and/or property + array index indicated by fully resolving the path 
- * ! Assumes all pointers provided are valid
- * > returns: True if path can be resolved to a valid "pointer + property" OR "pointer only"
- */
-bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *index)
+static bool rna_path_parse(PointerRNA *ptr, const char *path,
+                           PointerRNA *r_ptr, PropertyRNA **r_prop, int *index,
+                           const bool eval_pointer)
 {
        PropertyRNA *prop;
        PointerRNA curptr;
-       PointerRNA nextptr;  /* keep uninitialized, helps expose bugs in collection accessor functions */
        char fixedbuf[256], *token;
        int type;
 
@@ -4065,12 +4035,16 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr,
                 * C.object["someprop"]
                 */
 
+               if (!curptr.data)
+                       return false;
+
                /* look up property name in current struct */
                token = rna_path_token(&path, fixedbuf, sizeof(fixedbuf), use_id_prop);
 
                if (!token)
                        return false;
 
+               prop = NULL;
                if (use_id_prop) { /* look up property name in current struct */
                        IDProperty *group = RNA_struct_idprops(&curptr, 0);
                        if (group && rna_token_strip_quotes(token))
@@ -4092,26 +4066,35 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr,
                 * collection, otherwise return the property rna so that the
                 * caller can read the value of the property itself */
                switch (type) {
-                       case PROP_POINTER:
-                               nextptr = RNA_property_pointer_get(&curptr, prop);
-                               if (nextptr.data == NULL)
-                                       return false;
-                               
-                               curptr = nextptr;
-                               prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
-                               if (index) *index = -1;
+                       case PROP_POINTER: {
+                               /* resolve pointer if further path elements follow
+                                * or explicitly requested
+                                */
+                               if (eval_pointer || *path) {
+                                       PointerRNA nextptr = RNA_property_pointer_get(&curptr, prop);
+                                       
+                                       curptr = nextptr;
+                                       prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
+                                       if (index) *index = -1;
+                               }
                                break;
-                       case PROP_COLLECTION:
-                               if (!rna_path_resolve_collection_key(&path, &curptr, prop, &nextptr))
-                                       return false;
-                               
-                               curptr = nextptr;
-                               prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
-                               if (index) *index = -1;
+                       }
+                       case PROP_COLLECTION: {
+                               /* resolve pointer if further path elements follow or explicitly requested */
+                               if (eval_pointer || *path) {
+                                       PointerRNA nextptr;
+                                       if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr))
+                                               return false;
+                                       
+                                       curptr = nextptr;
+                                       prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
+                                       if (index) *index = -1;
+                               }
                                break;
+                       }
                        default:
                                if (index) {
-                                       if (!rna_path_resolve_array_index(&path, &curptr, prop, index))
+                                       if (!rna_path_parse_array_index(&path, &curptr, prop, index))
                                                return false;
                                }
                                break;
@@ -4124,6 +4107,65 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr,
        return true;
 }
 
+/**
+ * Resolve the given RNA Path to find the pointer and/or property indicated by fully resolving the path.
+ *
+ * \note Assumes all pointers provided are valid
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
+bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
+{
+       if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, true))
+               return false;
+
+       return r_ptr->data != NULL;
+}
+
+/**
+ * Resolve the given RNA Path to find the pointer and/or property + array index indicated by fully resolving the path.
+ *
+ * \note Assumes all pointers provided are valid.
+ * \return True if path can be resolved to a valid "pointer + property" OR "pointer only"
+ */
+bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+       if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, true))
+               return false;
+
+       return r_ptr->data != NULL;
+}
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ * \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
+{
+       if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, false))
+               return false;
+
+       return r_ptr->data != NULL && *r_prop != NULL;
+}
+
+/**
+ * Resolve the given RNA Path to find the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path.
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax.
+ *  \note Assumes all pointers provided are valid
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+       if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, false))
+               return false;
+
+       return r_ptr->data != NULL && *r_prop != NULL;
+}
+
 
 char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey)
 {