Cleanup: use '_len' instead of '_size' w/ BLI API
[blender.git] / source / blender / editors / space_outliner / outliner_tree.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2004 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_outliner/outliner_tree.c
29  *  \ingroup spoutliner
30  */
31  
32 #include <math.h>
33 #include <string.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_anim_types.h"
38 #include "DNA_armature_types.h"
39 #include "DNA_constraint_types.h"
40 #include "DNA_camera_types.h"
41 #include "DNA_cachefile_types.h"
42 #include "DNA_gpencil_types.h"
43 #include "DNA_group_types.h"
44 #include "DNA_key_types.h"
45 #include "DNA_lamp_types.h"
46 #include "DNA_material_types.h"
47 #include "DNA_mesh_types.h"
48 #include "DNA_meta_types.h"
49 #include "DNA_particle_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_world_types.h"
52 #include "DNA_sequence_types.h"
53 #include "DNA_speaker_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_linestyle_types.h"
56
57 #include "BLI_blenlib.h"
58 #include "BLI_utildefines.h"
59 #include "BLI_mempool.h"
60 #include "BLI_fnmatch.h"
61
62 #include "BLT_translation.h"
63
64 #include "BKE_fcurve.h"
65 #include "BKE_main.h"
66 #include "BKE_library.h"
67 #include "BKE_modifier.h"
68 #include "BKE_sequencer.h"
69 #include "BKE_idcode.h"
70 #include "BKE_outliner_treehash.h"
71
72 #include "ED_armature.h"
73 #include "ED_screen.h"
74
75 #include "WM_api.h"
76 #include "WM_types.h"
77
78 #include "RNA_access.h"
79
80 #include "outliner_intern.h"
81
82 #ifdef WIN32
83 #  include "BLI_math_base.h" /* M_PI */
84 #endif
85
86 /* ********************************************************* */
87 /* Persistent Data */
88
89 static void outliner_storage_cleanup(SpaceOops *soops)
90 {
91         BLI_mempool *ts = soops->treestore;
92         
93         if (ts) {
94                 TreeStoreElem *tselem;
95                 int unused = 0;
96                 
97                 /* each element used once, for ID blocks with more users to have each a treestore */
98                 BLI_mempool_iter iter;
99
100                 BLI_mempool_iternew(ts, &iter);
101                 while ((tselem = BLI_mempool_iterstep(&iter))) {
102                         tselem->used = 0;
103                 }
104                 
105                 /* cleanup only after reading file or undo step, and always for
106                  * RNA datablocks view in order to save memory */
107                 if (soops->storeflag & SO_TREESTORE_CLEANUP) {
108                         soops->storeflag &= ~SO_TREESTORE_CLEANUP;
109
110                         BLI_mempool_iternew(ts, &iter);
111                         while ((tselem = BLI_mempool_iterstep(&iter))) {
112                                 if (tselem->id == NULL) unused++;
113                         }
114                         
115                         if (unused) {
116                                 if (BLI_mempool_len(ts) == unused) {
117                                         BLI_mempool_destroy(ts);
118                                         soops->treestore = NULL;
119                                         if (soops->treehash) {
120                                                 BKE_outliner_treehash_free(soops->treehash);
121                                                 soops->treehash = NULL;
122                                         }
123                                 }
124                                 else {
125                                         TreeStoreElem *tsenew;
126                                         BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused,
127                                                                                  512, BLI_MEMPOOL_ALLOW_ITER);
128                                         BLI_mempool_iternew(ts, &iter);
129                                         while ((tselem = BLI_mempool_iterstep(&iter))) {
130                                                 if (tselem->id) {
131                                                         tsenew = BLI_mempool_alloc(new_ts);
132                                                         *tsenew = *tselem;
133                                                 }
134                                         }
135                                         BLI_mempool_destroy(ts);
136                                         soops->treestore = new_ts;
137                                         if (soops->treehash) {
138                                                 /* update hash table to fix broken pointers */
139                                                 BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
140                                         }
141                                 }
142                         }
143                 }
144         }
145 }
146
147 static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
148 {
149         TreeStoreElem *tselem;
150         
151         if (soops->treestore == NULL) {
152                 /* if treestore was not created in readfile.c, create it here */
153                 soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
154                 
155         }
156         if (soops->treehash == NULL) {
157                 soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
158         }
159
160         /* find any unused tree element in treestore and mark it as used
161          * (note that there may be multiple unused elements in case of linked objects) */
162         tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
163         if (tselem) {
164                 te->store_elem = tselem;
165                 tselem->used = 1;
166                 return;
167         }
168
169         /* add 1 element to treestore */
170         tselem = BLI_mempool_alloc(soops->treestore);
171         tselem->type = type;
172         tselem->nr = type ? nr : 0;
173         tselem->id = id;
174         tselem->used = 0;
175         tselem->flag = TSE_CLOSED;
176         te->store_elem = tselem;
177         BKE_outliner_treehash_add_element(soops->treehash, tselem);
178 }
179
180 /* ********************************************************* */
181 /* Tree Management */
182
183 void outliner_free_tree(ListBase *lb)
184 {
185         while (lb->first) {
186                 TreeElement *te = lb->first;
187                 
188                 outliner_free_tree(&te->subtree);
189                 BLI_remlink(lb, te);
190                 
191                 if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
192                 MEM_freeN(te);
193         }
194 }
195
196 void outliner_cleanup_tree(SpaceOops *soops)
197 {
198         outliner_free_tree(&soops->tree);
199         outliner_storage_cleanup(soops);
200 }
201
202 /* Find specific item from the treestore */
203 TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
204 {
205         TreeElement *te, *tes;
206         for (te = lb->first; te; te = te->next) {
207                 if (te->store_elem == store_elem) return te;
208                 tes = outliner_find_tree_element(&te->subtree, store_elem);
209                 if (tes) return tes;
210         }
211         return NULL;
212 }
213
214 /* tse is not in the treestore, we use its contents to find a match */
215 TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse)
216 {
217         TreeStoreElem *tselem;
218
219         if (tse->id == NULL) return NULL;
220         
221         /* check if 'tse' is in treestore */
222         tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
223         if (tselem) 
224                 return outliner_find_tree_element(&soops->tree, tselem);
225         
226         return NULL;
227 }
228
229 /* Find treestore that refers to given ID */
230 TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id)
231 {
232         for (TreeElement *te = lb->first; te; te = te->next) {
233                 TreeStoreElem *tselem = TREESTORE(te);
234                 if (tselem->type == 0) {
235                         if (tselem->id == id) {
236                                 return te;
237                         }
238                         /* only deeper on scene or object */
239                         if (ELEM(te->idcode, ID_OB, ID_SCE) ||
240                             ((soops->outlinevis == SO_GROUPS) && (te->idcode == ID_GR)))
241                         {
242                                 TreeElement *tes = outliner_find_id(soops, &te->subtree, id);
243                                 if (tes) {
244                                         return tes;
245                                 }
246                         }
247                 }
248         }
249         return NULL;
250 }
251
252 TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
253 {
254         for (TreeElement *te = lb->first; te; te = te->next) {
255                 if (te->directdata == pchan) {
256                         return te;
257                 }
258
259                 TreeStoreElem *tselem = TREESTORE(te);
260                 if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) {
261                         TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan);
262                         if (tes) {
263                                 return tes;
264                         }
265                 }
266         }
267         return NULL;
268 }
269
270 TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
271 {
272         for (TreeElement *te = lb->first; te; te = te->next) {
273                 if (te->directdata == ebone) {
274                         return te;
275                 }
276
277                 TreeStoreElem *tselem = TREESTORE(te);
278                 if (ELEM(tselem->type, 0, TSE_EBONE)) {
279                         TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
280                         if (tes) {
281                                 return tes;
282                         }
283                 }
284         }
285         return NULL;
286 }
287
288 ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
289 {
290         TreeStoreElem *tselem;
291         te = te->parent;
292         
293         while (te) {
294                 tselem = TREESTORE(te);
295                 if (tselem->type == 0 && te->idcode == idcode) return tselem->id;
296                 te = te->parent;
297         }
298         return NULL;
299 }
300
301
302 /* ********************************************************* */
303
304 /* Prototype, see functions below */
305 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, 
306                                          TreeElement *parent, short type, short index);
307
308 /* -------------------------------------------------------- */
309
310 /* special handling of hierarchical non-lib data */
311 static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
312                               TreeElement *parent, int *a)
313 {
314         TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
315         
316         (*a)++;
317         te->name = curBone->name;
318         te->directdata = curBone;
319         
320         for (curBone = curBone->childbase.first; curBone; curBone = curBone->next) {
321                 outliner_add_bone(soops, &te->subtree, id, curBone, te, a);
322         }
323 }
324
325 /* -------------------------------------------------------- */
326
327 #define LOG2I(x) (int)(log(x) / M_LN2)
328
329 static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl)
330 {
331         TreeStoreElem *tselem = NULL;
332         TreeElement *te = NULL;
333
334         /* log stuff is to convert bitflags (powers of 2) to small integers,
335          * in order to not overflow short tselem->nr */
336         
337         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_COMBINED));
338         te->name = IFACE_("Combined");
339         te->directdata = &srl->passflag;
340         
341         /* save cpu cycles, but we add the first to invoke an open/close triangle */
342         tselem = TREESTORE(tenla);
343         if (tselem->flag & TSE_CLOSED)
344                 return;
345         
346         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_Z));
347         te->name = IFACE_("Z");
348         te->directdata = &srl->passflag;
349
350         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_VECTOR));
351         te->name = IFACE_("Vector");
352         te->directdata = &srl->passflag;
353
354         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_NORMAL));
355         te->name = IFACE_("Normal");
356         te->directdata = &srl->passflag;
357
358         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_UV));
359         te->name = IFACE_("UV");
360         te->directdata = &srl->passflag;
361
362         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_MIST));
363         te->name = IFACE_("Mist");
364         te->directdata = &srl->passflag;
365
366         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXOB));
367         te->name = IFACE_("Index Object");
368         te->directdata = &srl->passflag;
369
370         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXMA));
371         te->name = IFACE_("Index Material");
372         te->directdata = &srl->passflag;
373
374         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_RGBA));
375         te->name = IFACE_("Color");
376         te->directdata = &srl->passflag;
377
378         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_DIFFUSE));
379         te->name = IFACE_("Diffuse");
380         te->directdata = &srl->passflag;
381
382         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SPEC));
383         te->name = IFACE_("Specular");
384         te->directdata = &srl->passflag;
385
386         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SHADOW));
387         te->name = IFACE_("Shadow");
388         te->directdata = &srl->passflag;
389
390         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_AO));
391         te->name = IFACE_("AO");
392         te->directdata = &srl->passflag;
393
394         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFLECT));
395         te->name = IFACE_("Reflection");
396         te->directdata = &srl->passflag;
397
398         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFRACT));
399         te->name = IFACE_("Refraction");
400         te->directdata = &srl->passflag;
401
402         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDIRECT));
403         te->name = IFACE_("Indirect");
404         te->directdata = &srl->passflag;
405
406         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_ENVIRONMENT));
407         te->name = IFACE_("Environment");
408         te->directdata = &srl->passflag;
409
410         te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_EMIT));
411         te->name = IFACE_("Emit");
412         te->directdata = &srl->passflag;
413 }
414
415 #undef LOG2I
416
417 static bool outliner_animdata_test(AnimData *adt)
418 {
419         if (adt)
420                 return (adt->action || adt->drivers.first || adt->nla_tracks.first);
421         return false;
422 }
423
424 #ifdef WITH_FREESTYLE
425 static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
426 {
427         SceneRenderLayer *srl;
428         FreestyleLineSet *lineset;
429
430         for (srl = sce->r.layers.first; srl; srl = srl->next) {
431                 for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
432                         FreestyleLineStyle *linestyle = lineset->linestyle;
433                         if (linestyle) {
434                                 linestyle->id.tag |= LIB_TAG_DOIT;
435                         }
436                 }
437         }
438         for (srl = sce->r.layers.first; srl; srl = srl->next) {
439                 for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
440                         FreestyleLineStyle *linestyle = lineset->linestyle;
441                         if (linestyle) {
442                                 if (!(linestyle->id.tag & LIB_TAG_DOIT))
443                                         continue;
444                                 linestyle->id.tag &= ~LIB_TAG_DOIT;
445                                 outliner_add_element(soops, lb, linestyle, te, 0, 0);
446                         }
447                 }
448         }
449 }
450 #endif
451
452 static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
453 {
454         SceneRenderLayer *srl;
455         TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
456         int a;
457         
458         tenla->name = IFACE_("RenderLayers");
459         for (a = 0, srl = sce->r.layers.first; srl; srl = srl->next, a++) {
460                 TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
461                 tenlay->name = srl->name;
462                 tenlay->directdata = &srl->layflag;
463                 
464                 if (srl->light_override)
465                         outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0);
466                 if (srl->mat_override)
467                         outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0);
468                 
469                 outliner_add_passes(soops, tenlay, &sce->id, srl);
470         }
471         
472         // TODO: move this to the front?
473         if (outliner_animdata_test(sce->adt))
474                 outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
475                 
476         outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
477         
478         outliner_add_element(soops,  lb, sce->world, te, 0, 0);
479
480 #ifdef WITH_FREESTYLE
481         if (STREQ(sce->r.engine, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS))
482                 outliner_add_line_styles(soops, lb, sce, te);
483 #endif
484 }
485
486 // can be inlined if necessary
487 static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
488 {
489         if (outliner_animdata_test(ob->adt))
490                 outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
491         
492         outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this
493         
494         if (ob->proxy && !ID_IS_LINKED(ob))
495                 outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
496                 
497         outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
498         
499         outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
500         
501         if (ob->pose) {
502                 bArmature *arm = ob->data;
503                 bPoseChannel *pchan;
504                 TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
505                 
506                 tenla->name = IFACE_("Pose");
507                 
508                 /* channels undefined in editmode, but we want the 'tenla' pose icon itself */
509                 if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
510                         TreeElement *ten;
511                         int a = 0, const_index = 1000;    /* ensure unique id for bone constraints */
512                         
513                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) {
514                                 ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
515                                 ten->name = pchan->name;
516                                 ten->directdata = pchan;
517                                 pchan->temp = (void *)ten;
518                                 
519                                 if (pchan->constraints.first) {
520                                         //Object *target;
521                                         bConstraint *con;
522                                         TreeElement *ten1;
523                                         TreeElement *tenla1 = outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
524                                         //char *str;
525                                         
526                                         tenla1->name = IFACE_("Constraints");
527                                         for (con = pchan->constraints.first; con; con = con->next, const_index++) {
528                                                 ten1 = outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
529 #if 0 /* disabled as it needs to be reworked for recoded constraints system */
530                                                 target = get_constraint_target(con, &str);
531                                                 if (str && str[0]) ten1->name = str;
532                                                 else if (target) ten1->name = target->id.name + 2;
533                                                 else ten1->name = con->name;
534 #endif
535                                                 ten1->name = con->name;
536                                                 ten1->directdata = con;
537                                                 /* possible add all other types links? */
538                                         }
539                                 }
540                         }
541                         /* make hierarchy */
542                         ten = tenla->subtree.first;
543                         while (ten) {
544                                 TreeElement *nten = ten->next, *par;
545                                 tselem = TREESTORE(ten);
546                                 if (tselem->type == TSE_POSE_CHANNEL) {
547                                         pchan = (bPoseChannel *)ten->directdata;
548                                         if (pchan->parent) {
549                                                 BLI_remlink(&tenla->subtree, ten);
550                                                 par = (TreeElement *)pchan->parent->temp;
551                                                 BLI_addtail(&par->subtree, ten);
552                                                 ten->parent = par;
553                                         }
554                                 }
555                                 ten = nten;
556                         }
557                 }
558                 
559                 /* Pose Groups */
560                 if (ob->pose->agroups.first) {
561                         bActionGroup *agrp;
562                         TreeElement *ten_bonegrp = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
563                         int a = 0;
564
565                         ten_bonegrp->name = IFACE_("Bone Groups");
566                         for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) {
567                                 TreeElement *ten;
568                                 ten = outliner_add_element(soops, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a);
569                                 ten->name = agrp->name;
570                                 ten->directdata = agrp;
571                         }
572                 }
573         }
574         
575         for (int a = 0; a < ob->totcol; a++) {
576                 outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
577         }
578         
579         if (ob->constraints.first) {
580                 //Object *target;
581                 bConstraint *con;
582                 TreeElement *ten;
583                 TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
584                 //char *str;
585                 int a;
586                 
587                 tenla->name = IFACE_("Constraints");
588                 for (con = ob->constraints.first, a = 0; con; con = con->next, a++) {
589                         ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
590 #if 0 /* disabled due to constraints system targets recode... code here needs review */
591                         target = get_constraint_target(con, &str);
592                         if (str && str[0]) ten->name = str;
593                         else if (target) ten->name = target->id.name + 2;
594                         else ten->name = con->name;
595 #endif
596                         ten->name = con->name;
597                         ten->directdata = con;
598                         /* possible add all other types links? */
599                 }
600         }
601         
602         if (ob->modifiers.first) {
603                 ModifierData *md;
604                 TreeElement *ten_mod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
605                 int index;
606                 
607                 ten_mod->name = IFACE_("Modifiers");
608                 for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) {
609                         TreeElement *ten = outliner_add_element(soops, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
610                         ten->name = md->name;
611                         ten->directdata = md;
612                         
613                         if (md->type == eModifierType_Lattice) {
614                                 outliner_add_element(soops, &ten->subtree, ((LatticeModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
615                         }
616                         else if (md->type == eModifierType_Curve) {
617                                 outliner_add_element(soops, &ten->subtree, ((CurveModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
618                         }
619                         else if (md->type == eModifierType_Armature) {
620                                 outliner_add_element(soops, &ten->subtree, ((ArmatureModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
621                         }
622                         else if (md->type == eModifierType_Hook) {
623                                 outliner_add_element(soops, &ten->subtree, ((HookModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
624                         }
625                         else if (md->type == eModifierType_ParticleSystem) {
626                                 ParticleSystem *psys = ((ParticleSystemModifierData *) md)->psys;
627                                 TreeElement *ten_psys;
628                                 
629                                 ten_psys = outliner_add_element(soops, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0);
630                                 ten_psys->directdata = psys;
631                                 ten_psys->name = psys->part->id.name + 2;
632                         }
633                 }
634         }
635         
636         /* vertex groups */
637         if (ob->defbase.first) {
638                 bDeformGroup *defgroup;
639                 TreeElement *ten;
640                 TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
641                 int a;
642                 
643                 tenla->name = IFACE_("Vertex Groups");
644                 for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) {
645                         ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
646                         ten->name = defgroup->name;
647                         ten->directdata = defgroup;
648                 }
649         }
650         
651         /* duplicated group */
652         if (ob->dup_group)
653                 outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
654 }
655
656
657 // can be inlined if necessary
658 static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, ID *id)
659 {
660         /* tuck pointer back in object, to construct hierarchy */
661         if (GS(id->name) == ID_OB) id->newid = (ID *)te;
662         
663         /* expand specific data always */
664         switch (GS(id->name)) {
665                 case ID_LI:
666                 {
667                         te->name = ((Library *)id)->name;
668                         break;
669                 }
670                 case ID_SCE:
671                 {
672                         outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
673                         break;
674                 }
675                 case ID_OB:
676                 {
677                         outliner_add_object_contents(soops, te, tselem, (Object *)id);
678                         break;
679                 }
680                 case ID_ME:
681                 {
682                         Mesh *me = (Mesh *)id;
683                         int a;
684                         
685                         if (outliner_animdata_test(me->adt))
686                                 outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0);
687                         
688                         outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
689                         for (a = 0; a < me->totcol; a++)
690                                 outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
691                         /* could do tfaces with image links, but the images are not grouped nicely.
692                          * would require going over all tfaces, sort images in use. etc... */
693                         break;
694                 }
695                 case ID_CU:
696                 {
697                         Curve *cu = (Curve *)id;
698                         int a;
699                         
700                         if (outliner_animdata_test(cu->adt))
701                                 outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0);
702                         
703                         for (a = 0; a < cu->totcol; a++)
704                                 outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
705                         break;
706                 }
707                 case ID_MB:
708                 {
709                         MetaBall *mb = (MetaBall *)id;
710                         int a;
711                         
712                         if (outliner_animdata_test(mb->adt))
713                                 outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0);
714                         
715                         for (a = 0; a < mb->totcol; a++)
716                                 outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
717                         break;
718                 }
719                 case ID_MA:
720                 {
721                         Material *ma = (Material *)id;
722                         int a;
723                         
724                         if (outliner_animdata_test(ma->adt))
725                                 outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
726                         
727                         for (a = 0; a < MAX_MTEX; a++) {
728                                 if (ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
729                         }
730                         break;
731                 }
732                 case ID_TE:
733                 {
734                         Tex *tex = (Tex *)id;
735                         
736                         if (outliner_animdata_test(tex->adt))
737                                 outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0);
738                         
739                         outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
740                         break;
741                 }
742                 case ID_CA:
743                 {
744                         Camera *ca = (Camera *)id;
745                         
746                         if (outliner_animdata_test(ca->adt))
747                                 outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0);
748                         break;
749                 }
750                 case ID_CF:
751                 {
752                         CacheFile *cache_file = (CacheFile *)id;
753
754                         if (outliner_animdata_test(cache_file->adt)) {
755                                 outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0);
756                         }
757
758                         break;
759                 }
760                 case ID_LA:
761                 {
762                         Lamp *la = (Lamp *)id;
763                         int a;
764                         
765                         if (outliner_animdata_test(la->adt))
766                                 outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0);
767                         
768                         for (a = 0; a < MAX_MTEX; a++) {
769                                 if (la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
770                         }
771                         break;
772                 }
773                 case ID_SPK:
774                 {
775                         Speaker *spk = (Speaker *)id;
776
777                         if (outliner_animdata_test(spk->adt))
778                                 outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
779                         break;
780                 }
781                 case ID_WO:
782                 {
783                         World *wrld = (World *)id;
784                         int a;
785                         
786                         if (outliner_animdata_test(wrld->adt))
787                                 outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
788                         
789                         for (a = 0; a < MAX_MTEX; a++) {
790                                 if (wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
791                         }
792                         break;
793                 }
794                 case ID_KE:
795                 {
796                         Key *key = (Key *)id;
797                         
798                         if (outliner_animdata_test(key->adt))
799                                 outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0);
800                         break;
801                 }
802                 case ID_AC:
803                 {
804                         // XXX do we want to be exposing the F-Curves here?
805                         //bAction *act = (bAction *)id;
806                         break;
807                 }
808                 case ID_AR:
809                 {
810                         bArmature *arm = (bArmature *)id;
811                         int a = 0;
812                         
813                         if (outliner_animdata_test(arm->adt))
814                                 outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
815                         
816                         if (arm->edbo) {
817                                 EditBone *ebone;
818                                 TreeElement *ten;
819                                 
820                                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next, a++) {
821                                         ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
822                                         ten->directdata = ebone;
823                                         ten->name = ebone->name;
824                                         ebone->temp.p = ten;
825                                 }
826                                 /* make hierarchy */
827                                 ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
828                                 while (ten) {
829                                         TreeElement *nten = ten->next, *par;
830                                         ebone = (EditBone *)ten->directdata;
831                                         if (ebone->parent) {
832                                                 BLI_remlink(&te->subtree, ten);
833                                                 par = ebone->parent->temp.p;
834                                                 BLI_addtail(&par->subtree, ten);
835                                                 ten->parent = par;
836                                         }
837                                         ten = nten;
838                                 }
839                         }
840                         else {
841                                 /* do not extend Armature when we have posemode */
842                                 tselem = TREESTORE(te->parent);
843                                 if (GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) {
844                                         /* pass */
845                                 }
846                                 else {
847                                         Bone *curBone;
848                                         for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
849                                                 outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
850                                         }
851                                 }
852                         }
853                         break;
854                 }
855                 case ID_LS:
856                 {
857                         FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
858                         int a;
859                         
860                         if (outliner_animdata_test(linestyle->adt))
861                                 outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
862
863                         for (a = 0; a < MAX_MTEX; a++) {
864                                 if (linestyle->mtex[a])
865                                         outliner_add_element(soops, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
866                         }
867                         break;
868                 }
869                 case ID_GD:
870                 {
871                         bGPdata *gpd = (bGPdata *)id;
872                         bGPDlayer *gpl;
873                         int a = 0;
874                         
875                         if (outliner_animdata_test(gpd->adt))
876                                 outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
877                         
878                         // TODO: base element for layers?
879                         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
880                                 outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a);
881                                 a++;
882                         }
883                         break;
884                 }
885                 default:
886                         break;
887         }
888 }
889
890 // TODO: this function needs to be split up! It's getting a bit too large...
891 // Note: "ID" is not always a real ID
892 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
893                                          TreeElement *parent, short type, short index)
894 {
895         TreeElement *te;
896         TreeStoreElem *tselem;
897         ID *id = idv;
898         
899         if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
900                 id = ((PointerRNA *)idv)->id.data;
901                 if (!id) id = ((PointerRNA *)idv)->data;
902         }
903         else if (type == TSE_GP_LAYER) {
904                 /* idv is the layer its self */
905                 id = TREESTORE(parent)->id;
906         }
907
908         /* One exception */
909         if (type == TSE_ID_BASE) {
910                 /* pass */
911         }
912         else if (id == NULL) {
913                 return NULL;
914         }
915
916         if (type == 0) {
917                 /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
918                 BLI_assert(TREESTORE_ID_TYPE(id));
919         }
920
921         te = MEM_callocN(sizeof(TreeElement), "tree elem");
922         /* add to the visual tree */
923         BLI_addtail(lb, te);
924         /* add to the storage */
925         check_persistent(soops, te, id, type, index);
926         tselem = TREESTORE(te);
927         
928         /* if we are searching for something expand to see child elements */
929         if (SEARCHING_OUTLINER(soops))
930                 tselem->flag |= TSE_CHILDSEARCH;
931         
932         te->parent = parent;
933         te->index = index;   // for data arays
934         if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
935                 /* pass */
936         }
937         else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
938                 /* pass */
939         }
940         else if (type == TSE_ANIM_DATA) {
941                 /* pass */
942         }
943         else if (type == TSE_GP_LAYER) {
944                 /* pass */
945         }
946         else if (type == TSE_ID_BASE) {
947                 /* pass */
948         }
949         else {
950                 /* do here too, for blend file viewer, own ID_LI then shows file name */
951                 if (GS(id->name) == ID_LI)
952                         te->name = ((Library *)id)->name;
953                 else
954                         te->name = id->name + 2; // default, can be overridden by Library or non-ID data
955                 te->idcode = GS(id->name);
956         }
957         
958         if (type == 0) {
959                 TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
960                 
961                 /* ID datablock */
962                 if (tsepar == NULL || tsepar->type != TSE_ID_BASE)
963                         outliner_add_id_contents(soops, te, tselem, id);
964         }
965         else if (type == TSE_ANIM_DATA) {
966                 IdAdtTemplate *iat = (IdAdtTemplate *)idv;
967                 AnimData *adt = (AnimData *)iat->adt;
968                 
969                 /* this element's info */
970                 te->name = IFACE_("Animation");
971                 te->directdata = adt;
972                 
973                 /* Action */
974                 outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
975                 
976                 /* Drivers */
977                 if (adt->drivers.first) {
978                         TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
979                         ID *lastadded = NULL;
980                         FCurve *fcu;
981                         
982                         ted->name = IFACE_("Drivers");
983                 
984                         for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
985                                 if (fcu->driver && fcu->driver->variables.first) {
986                                         ChannelDriver *driver = fcu->driver;
987                                         DriverVar *dvar;
988                                         
989                                         for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
990                                                 /* loop over all targets used here */
991                                                 DRIVER_TARGETS_USED_LOOPER(dvar) 
992                                                 {
993                                                         if (lastadded != dtar->id) {
994                                                                 // XXX this lastadded check is rather lame, and also fails quite badly...
995                                                                 outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
996                                                                 lastadded = dtar->id;
997                                                         }
998                                                 }
999                                                 DRIVER_TARGETS_LOOPER_END
1000                                         }
1001                                 }
1002                         }
1003                 }
1004                 
1005                 /* NLA Data */
1006                 if (adt->nla_tracks.first) {
1007                         TreeElement *tenla = outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0);
1008                         NlaTrack *nlt;
1009                         int a = 0;
1010                         
1011                         tenla->name = IFACE_("NLA Tracks");
1012                         
1013                         for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1014                                 TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
1015                                 NlaStrip *strip;
1016                                 TreeElement *ten;
1017                                 int b = 0;
1018                                 
1019                                 tenlt->name = nlt->name;
1020                                 
1021                                 for (strip = nlt->strips.first; strip; strip = strip->next, b++) {
1022                                         ten = outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b);
1023                                         if (ten) ten->directdata = strip;
1024                                 }
1025                         }
1026                 }
1027         }
1028         else if (type == TSE_GP_LAYER) {
1029                 bGPDlayer *gpl = (bGPDlayer *)idv;
1030                 
1031                 te->name = gpl->info;
1032                 te->directdata = gpl;
1033         }
1034         else if (type == TSE_SEQUENCE) {
1035                 Sequence *seq = (Sequence *) idv;
1036                 Sequence *p;
1037
1038                 /*
1039                  * The idcode is a little hack, but the outliner
1040                  * only check te->idcode if te->type is equal to zero,
1041                  * so this is "safe".
1042                  */
1043                 te->idcode = seq->type;
1044                 te->directdata = seq;
1045                 te->name = seq->name + 2;
1046
1047                 if (!(seq->type & SEQ_TYPE_EFFECT)) {
1048                         /*
1049                          * This work like the sequence.
1050                          * If the sequence have a name (not default name)
1051                          * show it, in other case put the filename.
1052                          */
1053
1054                         if (seq->type == SEQ_TYPE_META) {
1055                                 p = seq->seqbase.first;
1056                                 while (p) {
1057                                         outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
1058                                         p = p->next;
1059                                 }
1060                         }
1061                         else
1062                                 outliner_add_element(soops, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
1063                 }
1064         }
1065         else if (type == TSE_SEQ_STRIP) {
1066                 Strip *strip = (Strip *)idv;
1067
1068                 if (strip->dir[0] != '\0')
1069                         te->name = strip->dir;
1070                 else
1071                         te->name = IFACE_("Strip None");
1072                 te->directdata = strip;
1073         }
1074         else if (type == TSE_SEQUENCE_DUP) {
1075                 Sequence *seq = (Sequence *)idv;
1076
1077                 te->idcode = seq->type;
1078                 te->directdata = seq;
1079                 te->name = seq->strip->stripdata->name;
1080         }
1081         else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
1082                 PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
1083                 PropertyRNA *prop, *iterprop;
1084                 PropertyType proptype;
1085
1086                 /* Don't display arrays larger, weak but index is stored as a short,
1087                  * also the outliner isn't intended for editing such large data-sets. */
1088                 BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!");
1089                 const int tot_limit = SHRT_MAX;
1090
1091                 int a, tot;
1092
1093                 /* we do lazy build, for speed and to avoid infinite recusion */
1094
1095                 if (ptr->data == NULL) {
1096                         te->name = IFACE_("(empty)");
1097                 }
1098                 else if (type == TSE_RNA_STRUCT) {
1099                         /* struct */
1100                         te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
1101
1102                         if (te->name)
1103                                 te->flag |= TE_FREE_NAME;
1104                         else
1105                                 te->name = RNA_struct_ui_name(ptr->type);
1106
1107                         /* If searching don't expand RNA entries */
1108                         if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) tselem->flag &= ~TSE_CHILDSEARCH;
1109
1110                         iterprop = RNA_struct_iterator_property(ptr->type);
1111                         tot = RNA_property_collection_length(ptr, iterprop);
1112                         CLAMP_MAX(tot, tot_limit);
1113
1114                         /* auto open these cases */
1115                         if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER)
1116                                 if (!tselem->used)
1117                                         tselem->flag &= ~TSE_CLOSED;
1118
1119                         if (TSELEM_OPEN(tselem, soops)) {
1120                                 for (a = 0; a < tot; a++) {
1121                                         RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
1122                                         if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
1123                                                 outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
1124                                         }
1125                                 }
1126                         }
1127                         else if (tot)
1128                                 te->flag |= TE_LAZY_CLOSED;
1129
1130                         te->rnaptr = *ptr;
1131                 }
1132                 else if (type == TSE_RNA_PROPERTY) {
1133                         /* property */
1134                         iterprop = RNA_struct_iterator_property(ptr->type);
1135                         RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
1136
1137                         prop = propptr.data;
1138                         proptype = RNA_property_type(prop);
1139
1140                         te->name = RNA_property_ui_name(prop);
1141                         te->directdata = prop;
1142                         te->rnaptr = *ptr;
1143
1144                         /* If searching don't expand RNA entries */
1145                         if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) tselem->flag &= ~TSE_CHILDSEARCH;
1146
1147                         if (proptype == PROP_POINTER) {
1148                                 pptr = RNA_property_pointer_get(ptr, prop);
1149
1150                                 if (pptr.data) {
1151                                         if (TSELEM_OPEN(tselem, soops))
1152                                                 outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
1153                                         else
1154                                                 te->flag |= TE_LAZY_CLOSED;
1155                                 }
1156                         }
1157                         else if (proptype == PROP_COLLECTION) {
1158                                 tot = RNA_property_collection_length(ptr, prop);
1159                                 CLAMP_MAX(tot, tot_limit);
1160
1161                                 if (TSELEM_OPEN(tselem, soops)) {
1162                                         for (a = 0; a < tot; a++) {
1163                                                 RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
1164                                                 outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
1165                                         }
1166                                 }
1167                                 else if (tot)
1168                                         te->flag |= TE_LAZY_CLOSED;
1169                         }
1170                         else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
1171                                 tot = RNA_property_array_length(ptr, prop);
1172                                 CLAMP_MAX(tot, tot_limit);
1173
1174                                 if (TSELEM_OPEN(tselem, soops)) {
1175                                         for (a = 0; a < tot; a++)
1176                                                 outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
1177                                 }
1178                                 else if (tot)
1179                                         te->flag |= TE_LAZY_CLOSED;
1180                         }
1181                 }
1182                 else if (type == TSE_RNA_ARRAY_ELEM) {
1183                         char c;
1184
1185                         prop = parent->directdata;
1186
1187                         te->directdata = prop;
1188                         te->rnaptr = *ptr;
1189                         te->index = index;
1190
1191                         c = RNA_property_array_item_char(prop, index);
1192
1193                         te->name = MEM_callocN(sizeof(char) * 20, "OutlinerRNAArrayName");
1194                         if (c) sprintf((char *)te->name, "  %c", c);
1195                         else sprintf((char *)te->name, "  %d", index + 1);
1196                         te->flag |= TE_FREE_NAME;
1197                 }
1198         }
1199         else if (type == TSE_KEYMAP) {
1200                 wmKeyMap *km = (wmKeyMap *)idv;
1201                 wmKeyMapItem *kmi;
1202                 char opname[OP_MAX_TYPENAME];
1203                 
1204                 te->directdata = idv;
1205                 te->name = km->idname;
1206                 
1207                 if (TSELEM_OPEN(tselem, soops)) {
1208                         int a = 0;
1209                         
1210                         for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
1211                                 const char *key = WM_key_event_string(kmi->type, false);
1212                                 
1213                                 if (key[0]) {
1214                                         wmOperatorType *ot = NULL;
1215                                         
1216                                         if (kmi->propvalue) {
1217                                                 /* pass */
1218                                         }
1219                                         else {
1220                                                 ot = WM_operatortype_find(kmi->idname, 0);
1221                                         }
1222                                         
1223                                         if (ot || kmi->propvalue) {
1224                                                 TreeElement *ten = outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a);
1225                                                 
1226                                                 ten->directdata = kmi;
1227                                                 
1228                                                 if (kmi->propvalue) {
1229                                                         ten->name = IFACE_("Modal map, not yet");
1230                                                 }
1231                                                 else {
1232                                                         WM_operator_py_idname(opname, ot->idname);
1233                                                         ten->name = BLI_strdup(opname);
1234                                                         ten->flag |= TE_FREE_NAME;
1235                                                 }
1236                                         }
1237                                 }
1238                         }
1239                 }
1240                 else 
1241                         te->flag |= TE_LAZY_CLOSED;
1242         }
1243
1244         return te;
1245 }
1246
1247 /* ======================================================= */
1248 /* Sequencer mode tree building */
1249
1250 /* Helped function to put duplicate sequence in the same tree. */
1251 static int need_add_seq_dup(Sequence *seq)
1252 {
1253         Sequence *p;
1254
1255         if ((!seq->strip) || (!seq->strip->stripdata))
1256                 return(1);
1257
1258         /*
1259          * First check backward, if we found a duplicate
1260          * sequence before this, don't need it, just return.
1261          */
1262         p = seq->prev;
1263         while (p) {
1264                 if ((!p->strip) || (!p->strip->stripdata)) {
1265                         p = p->prev;
1266                         continue;
1267                 }
1268
1269                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
1270                         return(2);
1271                 p = p->prev;
1272         }
1273
1274         p = seq->next;
1275         while (p) {
1276                 if ((!p->strip) || (!p->strip->stripdata)) {
1277                         p = p->next;
1278                         continue;
1279                 }
1280
1281                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
1282                         return(0);
1283                 p = p->next;
1284         }
1285         return(1);
1286 }
1287
1288 static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *te, short index)
1289 {
1290         /* TreeElement *ch; */ /* UNUSED */
1291         Sequence *p;
1292
1293         p = seq;
1294         while (p) {
1295                 if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
1296                         p = p->next;
1297                         continue;
1298                 }
1299
1300                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
1301                         /* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
1302                 p = p->next;
1303         }
1304 }
1305
1306
1307 /* ----------------------------------------------- */
1308
1309
1310 static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
1311 {
1312         TreeElement *ten;
1313         ListBase *lbarray[MAX_LIBARRAY];
1314         int a, tot;
1315         
1316         tot = set_listbasepointers(mainvar, lbarray);
1317         for (a = 0; a < tot; a++) {
1318                 if (lbarray[a]->first) {
1319                         ID *id = lbarray[a]->first;
1320                         
1321                         /* check if there's data in current lib */
1322                         for (; id; id = id->next)
1323                                 if (id->lib == lib)
1324                                         break;
1325                         
1326                         if (id) {
1327                                 ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
1328                                 ten->directdata = lbarray[a];
1329                                 
1330                                 ten->name = BKE_idcode_to_name_plural(GS(id->name));
1331                                 if (ten->name == NULL)
1332                                         ten->name = "UNKNOWN";
1333                                 
1334                                 for (id = lbarray[a]->first; id; id = id->next) {
1335                                         if (id->lib == lib)
1336                                                 outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
1337                                 }
1338                         }
1339                 }
1340         }
1341         
1342 }
1343
1344 static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
1345 {
1346         TreeElement *ten;
1347         ListBase *lbarray[MAX_LIBARRAY];
1348         int a, tot;
1349         
1350         tot = set_listbasepointers(mainvar, lbarray);
1351         for (a = 0; a < tot; a++) {
1352                 if (lbarray[a]->first) {
1353                         ID *id = lbarray[a]->first;
1354                         
1355                         /* check if there are any datablocks of this type which are orphans */
1356                         for (; id; id = id->next) {
1357                                 if (ID_REAL_USERS(id) <= 0)
1358                                         break;
1359                         }
1360                         
1361                         if (id) {
1362                                 /* header for this type of datablock */
1363                                 /* TODO's:
1364                                  *   - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead?
1365                                  *   - Ensure that this uses nice icons for the datablock type involved instead of the dot?
1366                                  */
1367                                 ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
1368                                 ten->directdata = lbarray[a];
1369                                 
1370                                 ten->name = BKE_idcode_to_name_plural(GS(id->name));
1371                                 if (ten->name == NULL)
1372                                         ten->name = "UNKNOWN";
1373                                 
1374                                 /* add the orphaned datablocks - these will not be added with any subtrees attached */
1375                                 for (id = lbarray[a]->first; id; id = id->next) {
1376                                         if (ID_REAL_USERS(id) <= 0)
1377                                                 outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
1378                                 }
1379                         }
1380                 }
1381         }
1382 }
1383
1384 /* ======================================================= */
1385 /* Generic Tree Building helpers - order these are called is top to bottom */
1386
1387 /* Hierarchy --------------------------------------------- */
1388
1389 /* make sure elements are correctly nested */
1390 static void outliner_make_hierarchy(ListBase *lb)
1391 {
1392         TreeElement *te, *ten, *tep;
1393         TreeStoreElem *tselem;
1394
1395         /* build hierarchy */
1396         // XXX also, set extents here...
1397         te = lb->first;
1398         while (te) {
1399                 ten = te->next;
1400                 tselem = TREESTORE(te);
1401                 
1402                 if (tselem->type == 0 && te->idcode == ID_OB) {
1403                         Object *ob = (Object *)tselem->id;
1404                         if (ob->parent && ob->parent->id.newid) {
1405                                 BLI_remlink(lb, te);
1406                                 tep = (TreeElement *)ob->parent->id.newid;
1407                                 BLI_addtail(&tep->subtree, te);
1408                                 // set correct parent pointers
1409                                 for (te = tep->subtree.first; te; te = te->next) te->parent = tep;
1410                         }
1411                 }
1412                 te = ten;
1413         }
1414 }
1415
1416 /* Sorting ------------------------------------------------------ */
1417
1418 typedef struct tTreeSort {
1419         TreeElement *te;
1420         ID *id;
1421         const char *name;
1422         short idcode;
1423 } tTreeSort;
1424
1425 /* alphabetical comparator, tryping to put objects first */
1426 static int treesort_alpha_ob(const void *v1, const void *v2)
1427 {
1428         const tTreeSort *x1 = v1, *x2 = v2;
1429         int comp;
1430         
1431         /* first put objects last (hierarchy) */
1432         comp = (x1->idcode == ID_OB);
1433         if (x2->idcode == ID_OB) comp += 2;
1434         
1435         if (comp == 1) return 1;
1436         else if (comp == 2) return -1;
1437         else if (comp == 3) {
1438                 comp = strcmp(x1->name, x2->name);
1439                 
1440                 if (comp > 0) return 1;
1441                 else if (comp < 0) return -1;
1442                 return 0;
1443         }
1444         return 0;
1445 }
1446
1447 /* alphabetical comparator */
1448 static int treesort_alpha(const void *v1, const void *v2)
1449 {
1450         const tTreeSort *x1 = v1, *x2 = v2;
1451         int comp;
1452         
1453         comp = strcmp(x1->name, x2->name);
1454         
1455         if (comp > 0) return 1;
1456         else if (comp < 0) return -1;
1457         return 0;
1458 }
1459
1460
1461 /* this is nice option for later? doesnt look too useful... */
1462 #if 0
1463 static int treesort_obtype_alpha(const void *v1, const void *v2)
1464 {
1465         const tTreeSort *x1 = v1, *x2 = v2;
1466         
1467         /* first put objects last (hierarchy) */
1468         if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
1469                 return 1;
1470         }
1471         else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
1472                 return -1;
1473         }
1474         else {
1475                 /* 2nd we check ob type */
1476                 if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
1477                         if      (((Object *)x1->id)->type > ((Object *)x2->id)->type) return  1;
1478                         else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
1479                         else return 0;
1480                 }
1481                 else {
1482                         int comp = strcmp(x1->name, x2->name);
1483                         
1484                         if      (comp > 0) return  1;
1485                         else if (comp < 0) return -1;
1486                         return 0;
1487                 }
1488         }
1489 }
1490 #endif
1491
1492 /* sort happens on each subtree individual */
1493 static void outliner_sort(ListBase *lb)
1494 {
1495         TreeElement *te;
1496         TreeStoreElem *tselem;
1497         int totelem = 0;
1498
1499         te = lb->last;
1500         if (te == NULL) return;
1501         tselem = TREESTORE(te);
1502         
1503         /* sorting rules; only object lists, ID lists, or deformgroups */
1504         if ( ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) {
1505                 
1506                 /* count first */
1507                 for (te = lb->first; te; te = te->next) totelem++;
1508                 
1509                 if (totelem > 1) {
1510                         tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
1511                         tTreeSort *tp = tear;
1512                         int skip = 0;
1513
1514                         for (te = lb->first; te; te = te->next, tp++) {
1515                                 tselem = TREESTORE(te);
1516                                 tp->te = te;
1517                                 tp->name = te->name;
1518                                 tp->idcode = te->idcode;
1519                                 
1520                                 if (tselem->type && tselem->type != TSE_DEFGROUP)
1521                                         tp->idcode = 0;  // don't sort this
1522                                 if (tselem->type == TSE_ID_BASE)
1523                                         tp->idcode = 1; // do sort this
1524                                 
1525                                 tp->id = tselem->id;
1526                         }
1527                         
1528                         /* just sort alphabetically */
1529                         if (tear->idcode == 1) {
1530                                 qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
1531                         }
1532                         else {
1533                                 /* keep beginning of list */
1534                                 for (tp = tear, skip = 0; skip < totelem; skip++, tp++)
1535                                         if (tp->idcode) break;
1536                                 
1537                                 if (skip < totelem)
1538                                         qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
1539                         }
1540                         
1541                         BLI_listbase_clear(lb);
1542                         tp = tear;
1543                         while (totelem--) {
1544                                 BLI_addtail(lb, tp->te);
1545                                 tp++;
1546                         }
1547                         MEM_freeN(tear);
1548                 }
1549         }
1550         
1551         for (te = lb->first; te; te = te->next) {
1552                 outliner_sort(&te->subtree);
1553         }
1554 }
1555
1556 /* Filtering ----------------------------------------------- */
1557
1558 static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
1559 {
1560         int fn_flag = 0;
1561
1562         if ((flags & SO_FIND_CASE_SENSITIVE) == 0)
1563                 fn_flag |= FNM_CASEFOLD;
1564
1565         return fnmatch(name, te->name, fn_flag) == 0;
1566 }
1567
1568 static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
1569 {
1570         TreeElement *te, *ten;
1571         TreeStoreElem *tselem;
1572         char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
1573         char *search_string;
1574
1575         /* although we don't have any search string, we return true 
1576          * since the entire tree is ok then...
1577          */
1578         if (soops->search_string[0] == 0)
1579                 return 1;
1580
1581         if (soops->search_flags & SO_FIND_COMPLETE) {
1582                 search_string = soops->search_string;
1583         }
1584         else {
1585                 /* Implicitly add heading/trailing wildcards if needed. */
1586                 BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
1587                 search_string = search_buff;
1588         }
1589
1590         for (te = lb->first; te; te = ten) {
1591                 ten = te->next;
1592                 
1593                 if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
1594                         /* item isn't something we're looking for, but...
1595                          *  - if the subtree is expanded, check if there are any matches that can be easily found
1596                          *              so that searching for "cu" in the default scene will still match the Cube
1597                          *      - otherwise, we can't see within the subtree and the item doesn't match,
1598                          *              so these can be safely ignored (i.e. the subtree can get freed)
1599                          */
1600                         tselem = TREESTORE(te);
1601                         
1602                         /* flag as not a found item */
1603                         tselem->flag &= ~TSE_SEARCHMATCH;
1604                         
1605                         if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) {
1606                                 outliner_free_tree(&te->subtree);
1607                                 BLI_remlink(lb, te);
1608                                 
1609                                 if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
1610                                 MEM_freeN(te);
1611                         }
1612                 }
1613                 else {
1614                         tselem = TREESTORE(te);
1615                         
1616                         /* flag as a found item - we can then highlight it */
1617                         tselem->flag |= TSE_SEARCHMATCH;
1618                         
1619                         /* filter subtree too */
1620                         outliner_filter_tree(soops, &te->subtree);
1621                 }
1622         }
1623         
1624         /* if there are still items in the list, that means that there were still some matches */
1625         return (BLI_listbase_is_empty(lb) == false);
1626 }
1627
1628 /* ======================================================= */
1629 /* Main Tree Building API */
1630
1631 /* Main entry point for building the tree data-structure that the outliner represents */
1632 // TODO: split each mode into its own function?
1633 void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
1634 {
1635         Base *base;
1636         TreeElement *te = NULL, *ten;
1637         TreeStoreElem *tselem;
1638         int show_opened = !soops->treestore || !BLI_mempool_len(soops->treestore); /* on first view, we open scenes */
1639
1640         /* Are we looking for something - we want to tag parents to filter child matches
1641          * - NOT in datablocks view - searching all datablocks takes way too long to be useful
1642          * - this variable is only set once per tree build */
1643         if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATABLOCKS)
1644                 soops->search_flags |= SO_SEARCH_RECURSIVE;
1645         else
1646                 soops->search_flags &= ~SO_SEARCH_RECURSIVE;
1647
1648         if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
1649                 soops->storeflag &= ~SO_TREESTORE_REBUILD;
1650                 BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
1651         }
1652
1653         if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
1654                 return;
1655
1656         outliner_free_tree(&soops->tree);
1657         outliner_storage_cleanup(soops);
1658         
1659         /* options */
1660         if (soops->outlinevis == SO_LIBRARIES) {
1661                 Library *lib;
1662                 
1663                 /* current file first - mainvar provides tselem with unique pointer - not used */
1664                 ten = outliner_add_element(soops, &soops->tree, mainvar, NULL, TSE_ID_BASE, 0);
1665                 ten->name = IFACE_("Current File");
1666
1667                 tselem = TREESTORE(ten);
1668                 if (!tselem->used)
1669                         tselem->flag &= ~TSE_CLOSED;
1670                 
1671                 outliner_add_library_contents(mainvar, soops, ten, NULL);
1672                 
1673                 for (lib = mainvar->library.first; lib; lib = lib->id.next) {
1674                         ten = outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
1675                         lib->id.newid = (ID *)ten;
1676                         
1677                         outliner_add_library_contents(mainvar, soops, ten, lib);
1678
1679                 }
1680                 /* make hierarchy */
1681                 ten = soops->tree.first;
1682                 ten = ten->next;  /* first one is main */
1683                 while (ten) {
1684                         TreeElement *nten = ten->next, *par;
1685                         tselem = TREESTORE(ten);
1686                         lib = (Library *)tselem->id;
1687                         if (lib && lib->parent) {
1688                                 par = (TreeElement *)lib->parent->id.newid;
1689                                 if (tselem->id->tag & LIB_TAG_INDIRECT) {
1690                                         /* Only remove from 'first level' if lib is not also directly used. */
1691                                         BLI_remlink(&soops->tree, ten);
1692                                         BLI_addtail(&par->subtree, ten);
1693                                         ten->parent = par;
1694                                 }
1695                                 else {
1696                                         /* Else, make a new copy of the libtree for our parent. */
1697                                         TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0);
1698                                         outliner_add_library_contents(mainvar, soops, dupten, lib);
1699                                         dupten->parent = par;
1700                                 }
1701                         }
1702                         ten = nten;
1703                 }
1704                 /* restore newid pointers */
1705                 for (lib = mainvar->library.first; lib; lib = lib->id.next)
1706                         lib->id.newid = NULL;
1707                 
1708         }
1709         else if (soops->outlinevis == SO_ALL_SCENES) {
1710                 Scene *sce;
1711                 for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
1712                         te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
1713                         tselem = TREESTORE(te);
1714                         if (sce == scene && show_opened)
1715                                 tselem->flag &= ~TSE_CLOSED;
1716                         
1717                         for (base = sce->base.first; base; base = base->next) {
1718                                 ten = outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
1719                                 ten->directdata = base;
1720                         }
1721                         outliner_make_hierarchy(&te->subtree);
1722                         /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1723                         for (base = sce->base.first; base; base = base->next) base->object->id.newid = NULL;
1724                 }
1725         }
1726         else if (soops->outlinevis == SO_CUR_SCENE) {
1727                 
1728                 outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
1729                 
1730                 for (base = scene->base.first; base; base = base->next) {
1731                         ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1732                         ten->directdata = base;
1733                 }
1734                 outliner_make_hierarchy(&soops->tree);
1735         }
1736         else if (soops->outlinevis == SO_VISIBLE) {
1737                 for (base = scene->base.first; base; base = base->next) {
1738                         if (base->lay & scene->lay)
1739                                 outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1740                 }
1741                 outliner_make_hierarchy(&soops->tree);
1742         }
1743         else if (soops->outlinevis == SO_GROUPS) {
1744                 Group *group;
1745                 GroupObject *go;
1746                 
1747                 for (group = mainvar->group.first; group; group = group->id.next) {
1748                         if (group->gobject.first) {
1749                                 te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
1750                                 
1751                                 for (go = group->gobject.first; go; go = go->next) {
1752                                         ten = outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
1753                                         ten->directdata = NULL; /* eh, why? */
1754                                 }
1755                                 outliner_make_hierarchy(&te->subtree);
1756                                 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1757                                 for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
1758                         }
1759                 }
1760         }
1761         else if (soops->outlinevis == SO_SAME_TYPE) {
1762                 Object *ob = OBACT;
1763                 if (ob) {
1764                         for (base = scene->base.first; base; base = base->next) {
1765                                 if (base->object->type == ob->type) {
1766                                         ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1767                                         ten->directdata = base;
1768                                 }
1769                         }
1770                         outliner_make_hierarchy(&soops->tree);
1771                 }
1772         }
1773         else if (soops->outlinevis == SO_SELECTED) {
1774                 for (base = scene->base.first; base; base = base->next) {
1775                         if (base->lay & scene->lay) {
1776                                 if (base->flag & SELECT) {
1777                                         ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1778                                         ten->directdata = base;
1779                                 }
1780                         }
1781                 }
1782                 outliner_make_hierarchy(&soops->tree);
1783         }
1784         else if (soops->outlinevis == SO_SEQUENCE) {
1785                 Sequence *seq;
1786                 Editing *ed = BKE_sequencer_editing_get(scene, false);
1787                 int op;
1788
1789                 if (ed == NULL)
1790                         return;
1791
1792                 seq = ed->seqbasep->first;
1793                 if (!seq)
1794                         return;
1795
1796                 while (seq) {
1797                         op = need_add_seq_dup(seq);
1798                         if (op == 1) {
1799                                 /* ten = */ outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE, 0);
1800                         }
1801                         else if (op == 0) {
1802                                 ten = outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0);
1803                                 outliner_add_seq_dup(soops, seq, ten, 0);
1804                         }
1805                         seq = seq->next;
1806                 }
1807         }
1808         else if (soops->outlinevis == SO_DATABLOCKS) {
1809                 PointerRNA mainptr;
1810
1811                 RNA_main_pointer_create(mainvar, &mainptr);
1812
1813                 ten = outliner_add_element(soops, &soops->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1);
1814
1815                 if (show_opened) {
1816                         tselem = TREESTORE(ten);
1817                         tselem->flag &= ~TSE_CLOSED;
1818                 }
1819         }
1820         else if (soops->outlinevis == SO_USERDEF) {
1821                 PointerRNA userdefptr;
1822
1823                 RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr);
1824
1825                 ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
1826
1827                 if (show_opened) {
1828                         tselem = TREESTORE(ten);
1829                         tselem->flag &= ~TSE_CLOSED;
1830                 }
1831         }
1832         else if (soops->outlinevis == SO_ID_ORPHANS) {
1833                 outliner_add_orphaned_datablocks(mainvar, soops);
1834         }
1835         else {
1836                 ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
1837                 if (ten) ten->directdata = BASACT;
1838         }
1839
1840         if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
1841                 outliner_sort(&soops->tree);
1842         }
1843         outliner_filter_tree(soops, &soops->tree);
1844
1845         BKE_main_id_clear_newpoins(mainvar);
1846 }
1847
1848