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