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->view_render->engine_id, 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(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                 default:
847                         break;
848         }
849 }
850
851 // TODO: this function needs to be split up! It's getting a bit too large...
852 // Note: "ID" is not always a real ID
853 static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
854                                          TreeElement *parent, short type, short index)
855 {
856         TreeElement *te;
857         TreeStoreElem *tselem;
858         ID *id = idv;
859         
860         if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
861                 id = ((PointerRNA *)idv)->id.data;
862                 if (!id) id = ((PointerRNA *)idv)->data;
863         }
864         else if (type == TSE_GP_LAYER) {
865                 /* idv is the layer its self */
866                 id = TREESTORE(parent)->id;
867         }
868
869         /* exceptions */
870         if (ELEM(type, TSE_ID_BASE, TSE_LAYER_COLLECTION)) {
871                 /* pass */
872         }
873         else if (id == NULL) {
874                 return NULL;
875         }
876
877         if (type == 0) {
878                 /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
879                 BLI_assert(TREESTORE_ID_TYPE(id));
880         }
881
882         te = MEM_callocN(sizeof(TreeElement), "tree elem");
883         /* add to the visual tree */
884         BLI_addtail(lb, te);
885         /* add to the storage */
886         check_persistent(soops, te, id, type, index);
887         tselem = TREESTORE(te);
888         
889         /* if we are searching for something expand to see child elements */
890         if (SEARCHING_OUTLINER(soops))
891                 tselem->flag |= TSE_CHILDSEARCH;
892         
893         te->parent = parent;
894         te->index = index;   // for data arays
895         if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
896                 /* pass */
897         }
898         else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
899                 /* pass */
900         }
901         else if (type == TSE_ANIM_DATA) {
902                 /* pass */
903         }
904         else if (type == TSE_GP_LAYER) {
905                 /* pass */
906         }
907         else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
908                 /* pass */
909         }
910         else if (type == TSE_ID_BASE) {
911                 /* pass */
912         }
913         else {
914                 /* do here too, for blend file viewer, own ID_LI then shows file name */
915                 if (GS(id->name) == ID_LI)
916                         te->name = ((Library *)id)->name;
917                 else
918                         te->name = id->name + 2; // default, can be overridden by Library or non-ID data
919                 te->idcode = GS(id->name);
920         }
921         
922         if (type == 0) {
923                 TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
924                 
925                 /* ID datablock */
926                 if (tsepar == NULL || tsepar->type != TSE_ID_BASE)
927                         outliner_add_id_contents(soops, te, tselem, id);
928         }
929         else if (type == TSE_ANIM_DATA) {
930                 IdAdtTemplate *iat = (IdAdtTemplate *)idv;
931                 AnimData *adt = (AnimData *)iat->adt;
932                 
933                 /* this element's info */
934                 te->name = IFACE_("Animation");
935                 te->directdata = adt;
936                 
937                 /* Action */
938                 outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0);
939                 
940                 /* Drivers */
941                 if (adt->drivers.first) {
942                         TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
943                         ID *lastadded = NULL;
944                         FCurve *fcu;
945                         
946                         ted->name = IFACE_("Drivers");
947                 
948                         for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
949                                 if (fcu->driver && fcu->driver->variables.first) {
950                                         ChannelDriver *driver = fcu->driver;
951                                         DriverVar *dvar;
952                                         
953                                         for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
954                                                 /* loop over all targets used here */
955                                                 DRIVER_TARGETS_USED_LOOPER(dvar) 
956                                                 {
957                                                         if (lastadded != dtar->id) {
958                                                                 // XXX this lastadded check is rather lame, and also fails quite badly...
959                                                                 outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
960                                                                 lastadded = dtar->id;
961                                                         }
962                                                 }
963                                                 DRIVER_TARGETS_LOOPER_END
964                                         }
965                                 }
966                         }
967                 }
968                 
969                 /* NLA Data */
970                 if (adt->nla_tracks.first) {
971                         TreeElement *tenla = outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0);
972                         NlaTrack *nlt;
973                         int a = 0;
974                         
975                         tenla->name = IFACE_("NLA Tracks");
976                         
977                         for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
978                                 TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
979                                 NlaStrip *strip;
980                                 TreeElement *ten;
981                                 int b = 0;
982                                 
983                                 tenlt->name = nlt->name;
984                                 
985                                 for (strip = nlt->strips.first; strip; strip = strip->next, b++) {
986                                         ten = outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b);
987                                         if (ten) ten->directdata = strip;
988                                 }
989                         }
990                 }
991         }
992         else if (type == TSE_GP_LAYER) {
993                 bGPDlayer *gpl = (bGPDlayer *)idv;
994                 
995                 te->name = gpl->info;
996                 te->directdata = gpl;
997         }
998         else if (type == TSE_SEQUENCE) {
999                 Sequence *seq = (Sequence *) idv;
1000                 Sequence *p;
1001
1002                 /*
1003                  * The idcode is a little hack, but the outliner
1004                  * only check te->idcode if te->type is equal to zero,
1005                  * so this is "safe".
1006                  */
1007                 te->idcode = seq->type;
1008                 te->directdata = seq;
1009                 te->name = seq->name + 2;
1010
1011                 if (!(seq->type & SEQ_TYPE_EFFECT)) {
1012                         /*
1013                          * This work like the sequence.
1014                          * If the sequence have a name (not default name)
1015                          * show it, in other case put the filename.
1016                          */
1017
1018                         if (seq->type == SEQ_TYPE_META) {
1019                                 p = seq->seqbase.first;
1020                                 while (p) {
1021                                         outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
1022                                         p = p->next;
1023                                 }
1024                         }
1025                         else
1026                                 outliner_add_element(soops, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
1027                 }
1028         }
1029         else if (type == TSE_SEQ_STRIP) {
1030                 Strip *strip = (Strip *)idv;
1031
1032                 if (strip->dir[0] != '\0')
1033                         te->name = strip->dir;
1034                 else
1035                         te->name = IFACE_("Strip None");
1036                 te->directdata = strip;
1037         }
1038         else if (type == TSE_SEQUENCE_DUP) {
1039                 Sequence *seq = (Sequence *)idv;
1040
1041                 te->idcode = seq->type;
1042                 te->directdata = seq;
1043                 te->name = seq->strip->stripdata->name;
1044         }
1045         else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
1046                 PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
1047                 PropertyRNA *prop, *iterprop;
1048                 PropertyType proptype;
1049
1050                 /* Don't display arrays larger, weak but index is stored as a short,
1051                  * also the outliner isn't intended for editing such large data-sets. */
1052                 BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!");
1053                 const int tot_limit = SHRT_MAX;
1054
1055                 int a, tot;
1056
1057                 /* we do lazy build, for speed and to avoid infinite recusion */
1058
1059                 if (ptr->data == NULL) {
1060                         te->name = IFACE_("(empty)");
1061                 }
1062                 else if (type == TSE_RNA_STRUCT) {
1063                         /* struct */
1064                         te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
1065
1066                         if (te->name)
1067                                 te->flag |= TE_FREE_NAME;
1068                         else
1069                                 te->name = RNA_struct_ui_name(ptr->type);
1070
1071                         /* If searching don't expand RNA entries */
1072                         if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) tselem->flag &= ~TSE_CHILDSEARCH;
1073
1074                         iterprop = RNA_struct_iterator_property(ptr->type);
1075                         tot = RNA_property_collection_length(ptr, iterprop);
1076                         CLAMP_MAX(tot, tot_limit);
1077
1078                         /* auto open these cases */
1079                         if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER)
1080                                 if (!tselem->used)
1081                                         tselem->flag &= ~TSE_CLOSED;
1082
1083                         if (TSELEM_OPEN(tselem, soops)) {
1084                                 for (a = 0; a < tot; a++) {
1085                                         RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
1086                                         if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
1087                                                 outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
1088                                         }
1089                                 }
1090                         }
1091                         else if (tot)
1092                                 te->flag |= TE_LAZY_CLOSED;
1093
1094                         te->rnaptr = *ptr;
1095                 }
1096                 else if (type == TSE_RNA_PROPERTY) {
1097                         /* property */
1098                         iterprop = RNA_struct_iterator_property(ptr->type);
1099                         RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
1100
1101                         prop = propptr.data;
1102                         proptype = RNA_property_type(prop);
1103
1104                         te->name = RNA_property_ui_name(prop);
1105                         te->directdata = prop;
1106                         te->rnaptr = *ptr;
1107
1108                         /* If searching don't expand RNA entries */
1109                         if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) tselem->flag &= ~TSE_CHILDSEARCH;
1110
1111                         if (proptype == PROP_POINTER) {
1112                                 pptr = RNA_property_pointer_get(ptr, prop);
1113
1114                                 if (pptr.data) {
1115                                         if (TSELEM_OPEN(tselem, soops))
1116                                                 outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
1117                                         else
1118                                                 te->flag |= TE_LAZY_CLOSED;
1119                                 }
1120                         }
1121                         else if (proptype == PROP_COLLECTION) {
1122                                 tot = RNA_property_collection_length(ptr, prop);
1123                                 CLAMP_MAX(tot, tot_limit);
1124
1125                                 if (TSELEM_OPEN(tselem, soops)) {
1126                                         for (a = 0; a < tot; a++) {
1127                                                 RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
1128                                                 outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
1129                                         }
1130                                 }
1131                                 else if (tot)
1132                                         te->flag |= TE_LAZY_CLOSED;
1133                         }
1134                         else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
1135                                 tot = RNA_property_array_length(ptr, prop);
1136                                 CLAMP_MAX(tot, tot_limit);
1137
1138                                 if (TSELEM_OPEN(tselem, soops)) {
1139                                         for (a = 0; a < tot; a++)
1140                                                 outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
1141                                 }
1142                                 else if (tot)
1143                                         te->flag |= TE_LAZY_CLOSED;
1144                         }
1145                 }
1146                 else if (type == TSE_RNA_ARRAY_ELEM) {
1147                         char c;
1148
1149                         prop = parent->directdata;
1150
1151                         te->directdata = prop;
1152                         te->rnaptr = *ptr;
1153                         te->index = index;
1154
1155                         c = RNA_property_array_item_char(prop, index);
1156
1157                         te->name = MEM_callocN(sizeof(char) * 20, "OutlinerRNAArrayName");
1158                         if (c) sprintf((char *)te->name, "  %c", c);
1159                         else sprintf((char *)te->name, "  %d", index + 1);
1160                         te->flag |= TE_FREE_NAME;
1161                 }
1162         }
1163         else if (type == TSE_KEYMAP) {
1164                 wmKeyMap *km = (wmKeyMap *)idv;
1165                 wmKeyMapItem *kmi;
1166                 char opname[OP_MAX_TYPENAME];
1167                 
1168                 te->directdata = idv;
1169                 te->name = km->idname;
1170                 
1171                 if (TSELEM_OPEN(tselem, soops)) {
1172                         int a = 0;
1173                         
1174                         for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
1175                                 const char *key = WM_key_event_string(kmi->type, false);
1176                                 
1177                                 if (key[0]) {
1178                                         wmOperatorType *ot = NULL;
1179                                         
1180                                         if (kmi->propvalue) {
1181                                                 /* pass */
1182                                         }
1183                                         else {
1184                                                 ot = WM_operatortype_find(kmi->idname, 0);
1185                                         }
1186                                         
1187                                         if (ot || kmi->propvalue) {
1188                                                 TreeElement *ten = outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a);
1189                                                 
1190                                                 ten->directdata = kmi;
1191                                                 
1192                                                 if (kmi->propvalue) {
1193                                                         ten->name = IFACE_("Modal map, not yet");
1194                                                 }
1195                                                 else {
1196                                                         WM_operator_py_idname(opname, ot->idname);
1197                                                         ten->name = BLI_strdup(opname);
1198                                                         ten->flag |= TE_FREE_NAME;
1199                                                 }
1200                                         }
1201                                 }
1202                         }
1203                 }
1204                 else 
1205                         te->flag |= TE_LAZY_CLOSED;
1206         }
1207
1208         return te;
1209 }
1210
1211 /**
1212  * \note Really only removes \a tselem, not it's TreeElement instance or any children.
1213  */
1214 void outliner_remove_treestore_element(SpaceOops *soops, TreeStoreElem *tselem)
1215 {
1216         BKE_outliner_treehash_remove_element(soops->treehash, tselem);
1217         BLI_mempool_free(soops->treestore, tselem);
1218 }
1219
1220 /* ======================================================= */
1221 /* Sequencer mode tree building */
1222
1223 /* Helped function to put duplicate sequence in the same tree. */
1224 static int need_add_seq_dup(Sequence *seq)
1225 {
1226         Sequence *p;
1227
1228         if ((!seq->strip) || (!seq->strip->stripdata))
1229                 return(1);
1230
1231         /*
1232          * First check backward, if we found a duplicate
1233          * sequence before this, don't need it, just return.
1234          */
1235         p = seq->prev;
1236         while (p) {
1237                 if ((!p->strip) || (!p->strip->stripdata)) {
1238                         p = p->prev;
1239                         continue;
1240                 }
1241
1242                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
1243                         return(2);
1244                 p = p->prev;
1245         }
1246
1247         p = seq->next;
1248         while (p) {
1249                 if ((!p->strip) || (!p->strip->stripdata)) {
1250                         p = p->next;
1251                         continue;
1252                 }
1253
1254                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
1255                         return(0);
1256                 p = p->next;
1257         }
1258         return(1);
1259 }
1260
1261 static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *te, short index)
1262 {
1263         /* TreeElement *ch; */ /* UNUSED */
1264         Sequence *p;
1265
1266         p = seq;
1267         while (p) {
1268                 if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
1269                         p = p->next;
1270                         continue;
1271                 }
1272
1273                 if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
1274                         /* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
1275                 p = p->next;
1276         }
1277 }
1278
1279
1280 /* ----------------------------------------------- */
1281
1282
1283 static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
1284 {
1285         TreeElement *ten;
1286         ListBase *lbarray[MAX_LIBARRAY];
1287         int a, tot;
1288         
1289         tot = set_listbasepointers(mainvar, lbarray);
1290         for (a = 0; a < tot; a++) {
1291                 if (lbarray[a]->first) {
1292                         ID *id = lbarray[a]->first;
1293                         
1294                         /* check if there's data in current lib */
1295                         for (; id; id = id->next)
1296                                 if (id->lib == lib)
1297                                         break;
1298                         
1299                         if (id) {
1300                                 ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
1301                                 ten->directdata = lbarray[a];
1302                                 
1303                                 ten->name = BKE_idcode_to_name_plural(GS(id->name));
1304                                 if (ten->name == NULL)
1305                                         ten->name = "UNKNOWN";
1306                                 
1307                                 for (id = lbarray[a]->first; id; id = id->next) {
1308                                         if (id->lib == lib)
1309                                                 outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
1310                                 }
1311                         }
1312                 }
1313         }
1314         
1315 }
1316
1317 static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
1318 {
1319         TreeElement *ten;
1320         ListBase *lbarray[MAX_LIBARRAY];
1321         int a, tot;
1322         
1323         tot = set_listbasepointers(mainvar, lbarray);
1324         for (a = 0; a < tot; a++) {
1325                 if (lbarray[a]->first) {
1326                         ID *id = lbarray[a]->first;
1327                         
1328                         /* check if there are any datablocks of this type which are orphans */
1329                         for (; id; id = id->next) {
1330                                 if (ID_REAL_USERS(id) <= 0)
1331                                         break;
1332                         }
1333                         
1334                         if (id) {
1335                                 /* header for this type of datablock */
1336                                 /* TODO's:
1337                                  *   - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead?
1338                                  *   - Ensure that this uses nice icons for the datablock type involved instead of the dot?
1339                                  */
1340                                 ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
1341                                 ten->directdata = lbarray[a];
1342                                 
1343                                 ten->name = BKE_idcode_to_name_plural(GS(id->name));
1344                                 if (ten->name == NULL)
1345                                         ten->name = "UNKNOWN";
1346                                 
1347                                 /* add the orphaned datablocks - these will not be added with any subtrees attached */
1348                                 for (id = lbarray[a]->first; id; id = id->next) {
1349                                         if (ID_REAL_USERS(id) <= 0)
1350                                                 outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
1351                                 }
1352                         }
1353                 }
1354         }
1355 }
1356
1357 static void outliner_layer_collections_reorder(
1358         Main *bmain, const Scene *scene,
1359         TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
1360 {
1361         LayerCollection *lc_insert = insert_element->directdata;
1362         LayerCollection *lc_handle = insert_handle->directdata;
1363
1364         if (action == TE_INSERT_BEFORE) {
1365                 BKE_layer_collection_move_above(scene, lc_handle, lc_insert);
1366         }
1367         else if (action == TE_INSERT_AFTER) {
1368                 BKE_layer_collection_move_below(scene, lc_handle, lc_insert);
1369         }
1370         else if (action == TE_INSERT_INTO) {
1371                 BKE_layer_collection_move_into(scene, lc_handle, lc_insert);
1372         }
1373         else {
1374                 BLI_assert(0);
1375         }
1376
1377         DEG_relations_tag_update(bmain);
1378 }
1379 static bool outliner_layer_collections_reorder_poll(
1380         const Scene *UNUSED(scene), const TreeElement *UNUSED(insert_element),
1381         TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action))
1382 {
1383         const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
1384         return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION);
1385 }
1386
1387 static void outliner_add_layer_collections_recursive(
1388         SpaceOops *soops, ListBase *tree, ListBase *layer_collections, TreeElement *parent_ten)
1389 {
1390         for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) {
1391                 TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_LAYER_COLLECTION, 0);
1392
1393                 ten->name = collection->scene_collection->name;
1394                 ten->directdata = collection;
1395                 ten->reinsert = outliner_layer_collections_reorder;
1396                 ten->reinsert_poll = outliner_layer_collections_reorder_poll;
1397
1398                 outliner_add_layer_collections_recursive(soops, &ten->subtree, &collection->layer_collections, ten);
1399                 for (LinkData *link = collection->object_bases.first; link; link = link->next) {
1400                         Base *base = (Base *)link->data;
1401                         TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0);
1402                         te_object->directdata = base;
1403                 }
1404                 outliner_make_hierarchy(&ten->subtree);
1405         }
1406 }
1407 static void outliner_add_collections_act_layer(SpaceOops *soops, SceneLayer *layer)
1408 {
1409         outliner_add_layer_collections_recursive(soops, &soops->tree, &layer->layer_collections, NULL);
1410 }
1411
1412 static void outliner_scene_collections_reorder(
1413         Main *bmain, const Scene *scene,
1414         TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
1415 {
1416         SceneCollection *sc_insert = insert_element->directdata;
1417         SceneCollection *sc_handle = insert_handle->directdata;
1418
1419         BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(scene)));
1420         if (action == TE_INSERT_BEFORE) {
1421                 BKE_collection_move_above(scene, sc_handle, sc_insert);
1422         }
1423         else if (action == TE_INSERT_AFTER) {
1424                 BKE_collection_move_below(scene, sc_handle, sc_insert);
1425         }
1426         else if (action == TE_INSERT_INTO) {
1427                 BKE_collection_move_into(scene, sc_handle, sc_insert);
1428         }
1429         else {
1430                 BLI_assert(0);
1431         }
1432
1433         DEG_relations_tag_update(bmain);
1434 }
1435 static bool outliner_scene_collections_reorder_poll(
1436         const Scene *scene, const TreeElement *UNUSED(insert_element),
1437         TreeElement **io_insert_handle, TreeElementInsertType *io_action)
1438 {
1439         const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
1440         SceneCollection *sc_master = BKE_collection_master(scene);
1441         SceneCollection *sc_handle = (*io_insert_handle)->directdata;
1442
1443         if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) {
1444                 return false;
1445         }
1446
1447         if (sc_handle == sc_master) {
1448                 /* exception: Can't insert before/after master selection, has to be one of its childs */
1449                 TreeElement *te_master = *io_insert_handle;
1450                 if (*io_action == TE_INSERT_BEFORE) {
1451                         /* can't go higher than master collection, insert into it */
1452                         *io_action = TE_INSERT_INTO;
1453                 }
1454                 else if (*io_action == TE_INSERT_AFTER) {
1455                         *io_insert_handle = te_master->subtree.last;
1456                 }
1457         }
1458         return true;
1459 }
1460
1461 static void outliner_add_scene_collection_objects(
1462         SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent)
1463 {
1464         for (LinkData *link = collection->objects.first; link; link = link->next) {
1465                 outliner_add_element(soops, tree, link->data, parent, 0, 0);
1466         }
1467         outliner_make_hierarchy(tree);
1468 }
1469
1470 static void outliner_add_scene_collections_recursive(
1471         SpaceOops *soops, ListBase *tree, ListBase *scene_collections, TreeElement *parent_ten)
1472 {
1473         for (SceneCollection *collection = scene_collections->first; collection; collection = collection->next) {
1474                 TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_SCENE_COLLECTION, 0);
1475
1476                 ten->name = collection->name;
1477                 ten->directdata = collection;
1478                 ten->reinsert = outliner_scene_collections_reorder;
1479                 ten->reinsert_poll = outliner_scene_collections_reorder_poll;
1480
1481                 outliner_add_scene_collections_recursive(soops, &ten->subtree, &collection->scene_collections, ten);
1482                 outliner_add_scene_collection_objects(soops, &ten->subtree, collection, ten);
1483         }
1484 }
1485 static void outliner_add_collections_master(SpaceOops *soops, Scene *scene)
1486 {
1487         SceneCollection *master = BKE_collection_master(scene);
1488         outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL);
1489         outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL);
1490 }
1491
1492 /* ======================================================= */
1493 /* Generic Tree Building helpers - order these are called is top to bottom */
1494
1495 /* Hierarchy --------------------------------------------- */
1496
1497 /* make sure elements are correctly nested */
1498 static void outliner_make_hierarchy(ListBase *lb)
1499 {
1500         TreeElement *te, *ten, *tep;
1501         TreeStoreElem *tselem;
1502
1503         /* build hierarchy */
1504         // XXX also, set extents here...
1505         te = lb->first;
1506         while (te) {
1507                 ten = te->next;
1508                 tselem = TREESTORE(te);
1509                 
1510                 if (tselem->type == 0 && te->idcode == ID_OB) {
1511                         Object *ob = (Object *)tselem->id;
1512                         if (ob->parent && ob->parent->id.newid) {
1513                                 BLI_remlink(lb, te);
1514                                 tep = (TreeElement *)ob->parent->id.newid;
1515                                 BLI_addtail(&tep->subtree, te);
1516                                 // set correct parent pointers
1517                                 for (te = tep->subtree.first; te; te = te->next) te->parent = tep;
1518                         }
1519                 }
1520                 te = ten;
1521         }
1522 }
1523
1524 /* Sorting ------------------------------------------------------ */
1525
1526 typedef struct tTreeSort {
1527         TreeElement *te;
1528         ID *id;
1529         const char *name;
1530         short idcode;
1531 } tTreeSort;
1532
1533 /* alphabetical comparator, tryping to put objects first */
1534 static int treesort_alpha_ob(const void *v1, const void *v2)
1535 {
1536         const tTreeSort *x1 = v1, *x2 = v2;
1537         int comp;
1538         
1539         /* first put objects last (hierarchy) */
1540         comp = (x1->idcode == ID_OB);
1541         if (x2->idcode == ID_OB) comp += 2;
1542         
1543         if (comp == 1) return 1;
1544         else if (comp == 2) return -1;
1545         else if (comp == 3) {
1546                 comp = strcmp(x1->name, x2->name);
1547                 
1548                 if (comp > 0) return 1;
1549                 else if (comp < 0) return -1;
1550                 return 0;
1551         }
1552         return 0;
1553 }
1554
1555 /* alphabetical comparator */
1556 static int treesort_alpha(const void *v1, const void *v2)
1557 {
1558         const tTreeSort *x1 = v1, *x2 = v2;
1559         int comp;
1560         
1561         comp = strcmp(x1->name, x2->name);
1562         
1563         if (comp > 0) return 1;
1564         else if (comp < 0) return -1;
1565         return 0;
1566 }
1567
1568
1569 /* this is nice option for later? doesnt look too useful... */
1570 #if 0
1571 static int treesort_obtype_alpha(const void *v1, const void *v2)
1572 {
1573         const tTreeSort *x1 = v1, *x2 = v2;
1574         
1575         /* first put objects last (hierarchy) */
1576         if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
1577                 return 1;
1578         }
1579         else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
1580                 return -1;
1581         }
1582         else {
1583                 /* 2nd we check ob type */
1584                 if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
1585                         if      (((Object *)x1->id)->type > ((Object *)x2->id)->type) return  1;
1586                         else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
1587                         else return 0;
1588                 }
1589                 else {
1590                         int comp = strcmp(x1->name, x2->name);
1591                         
1592                         if      (comp > 0) return  1;
1593                         else if (comp < 0) return -1;
1594                         return 0;
1595                 }
1596         }
1597 }
1598 #endif
1599
1600 /* sort happens on each subtree individual */
1601 static void outliner_sort(ListBase *lb)
1602 {
1603         TreeElement *te;
1604         TreeStoreElem *tselem;
1605
1606         te = lb->last;
1607         if (te == NULL) return;
1608         tselem = TREESTORE(te);
1609
1610         /* sorting rules; only object lists, ID lists, or deformgroups */
1611         if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) {
1612                 int totelem = BLI_listbase_count(lb);
1613
1614                 if (totelem > 1) {
1615                         tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
1616                         tTreeSort *tp = tear;
1617                         int skip = 0;
1618
1619                         for (te = lb->first; te; te = te->next, tp++) {
1620                                 tselem = TREESTORE(te);
1621                                 tp->te = te;
1622                                 tp->name = te->name;
1623                                 tp->idcode = te->idcode;
1624                                 
1625                                 if (tselem->type && tselem->type != TSE_DEFGROUP)
1626                                         tp->idcode = 0;  // don't sort this
1627                                 if (tselem->type == TSE_ID_BASE)
1628                                         tp->idcode = 1; // do sort this
1629                                 
1630                                 tp->id = tselem->id;
1631                         }
1632                         
1633                         /* just sort alphabetically */
1634                         if (tear->idcode == 1) {
1635                                 qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
1636                         }
1637                         else {
1638                                 /* keep beginning of list */
1639                                 for (tp = tear, skip = 0; skip < totelem; skip++, tp++)
1640                                         if (tp->idcode) break;
1641                                 
1642                                 if (skip < totelem)
1643                                         qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
1644                         }
1645                         
1646                         BLI_listbase_clear(lb);
1647                         tp = tear;
1648                         while (totelem--) {
1649                                 BLI_addtail(lb, tp->te);
1650                                 tp++;
1651                         }
1652                         MEM_freeN(tear);
1653                 }
1654         }
1655         
1656         for (te = lb->first; te; te = te->next) {
1657                 outliner_sort(&te->subtree);
1658         }
1659 }
1660
1661 /* Filtering ----------------------------------------------- */
1662
1663 static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
1664 {
1665         int fn_flag = 0;
1666
1667         if ((flags & SO_FIND_CASE_SENSITIVE) == 0)
1668                 fn_flag |= FNM_CASEFOLD;
1669
1670         return fnmatch(name, te->name, fn_flag) == 0;
1671 }
1672
1673 static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
1674 {
1675         TreeElement *te, *ten;
1676         TreeStoreElem *tselem;
1677         char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
1678         char *search_string;
1679
1680         /* although we don't have any search string, we return true 
1681          * since the entire tree is ok then...
1682          */
1683         if (soops->search_string[0] == 0)
1684                 return 1;
1685
1686         if (soops->search_flags & SO_FIND_COMPLETE) {
1687                 search_string = soops->search_string;
1688         }
1689         else {
1690                 /* Implicitly add heading/trailing wildcards if needed. */
1691                 BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
1692                 search_string = search_buff;
1693         }
1694
1695         for (te = lb->first; te; te = ten) {
1696                 ten = te->next;
1697                 
1698                 if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
1699                         /* item isn't something we're looking for, but...
1700                          *  - if the subtree is expanded, check if there are any matches that can be easily found
1701                          *              so that searching for "cu" in the default scene will still match the Cube
1702                          *      - otherwise, we can't see within the subtree and the item doesn't match,
1703                          *              so these can be safely ignored (i.e. the subtree can get freed)
1704                          */
1705                         tselem = TREESTORE(te);
1706                         
1707                         /* flag as not a found item */
1708                         tselem->flag &= ~TSE_SEARCHMATCH;
1709                         
1710                         if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) {
1711                                 outliner_free_tree(&te->subtree);
1712                                 BLI_remlink(lb, te);
1713                                 
1714                                 if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
1715                                 MEM_freeN(te);
1716                         }
1717                 }
1718                 else {
1719                         tselem = TREESTORE(te);
1720                         
1721                         /* flag as a found item - we can then highlight it */
1722                         tselem->flag |= TSE_SEARCHMATCH;
1723                         
1724                         /* filter subtree too */
1725                         outliner_filter_tree(soops, &te->subtree);
1726                 }
1727         }
1728         
1729         /* if there are still items in the list, that means that there were still some matches */
1730         return (BLI_listbase_is_empty(lb) == false);
1731 }
1732
1733 /* ======================================================= */
1734 /* Main Tree Building API */
1735
1736 /* Main entry point for building the tree data-structure that the outliner represents */
1737 // TODO: split each mode into its own function?
1738 void outliner_build_tree(Main *mainvar, Scene *scene, SceneLayer *sl, SpaceOops *soops)
1739 {
1740         TreeElement *te = NULL, *ten;
1741         TreeStoreElem *tselem;
1742         int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */
1743
1744         /* Are we looking for something - we want to tag parents to filter child matches
1745          * - NOT in datablocks view - searching all datablocks takes way too long to be useful
1746          * - this variable is only set once per tree build */
1747         if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATABLOCKS)
1748                 soops->search_flags |= SO_SEARCH_RECURSIVE;
1749         else
1750                 soops->search_flags &= ~SO_SEARCH_RECURSIVE;
1751
1752         if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
1753                 soops->storeflag &= ~SO_TREESTORE_REBUILD;
1754                 BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
1755         }
1756
1757         if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
1758                 return;
1759
1760         outliner_free_tree(&soops->tree);
1761         outliner_storage_cleanup(soops);
1762         
1763         /* options */
1764         if (soops->outlinevis == SO_LIBRARIES) {
1765                 Library *lib;
1766                 
1767                 /* current file first - mainvar provides tselem with unique pointer - not used */
1768                 ten = outliner_add_element(soops, &soops->tree, mainvar, NULL, TSE_ID_BASE, 0);
1769                 ten->name = IFACE_("Current File");
1770
1771                 tselem = TREESTORE(ten);
1772                 if (!tselem->used)
1773                         tselem->flag &= ~TSE_CLOSED;
1774                 
1775                 outliner_add_library_contents(mainvar, soops, ten, NULL);
1776                 
1777                 for (lib = mainvar->library.first; lib; lib = lib->id.next) {
1778                         ten = outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
1779                         lib->id.newid = (ID *)ten;
1780                         
1781                         outliner_add_library_contents(mainvar, soops, ten, lib);
1782
1783                 }
1784                 /* make hierarchy */
1785                 ten = soops->tree.first;
1786                 ten = ten->next;  /* first one is main */
1787                 while (ten) {
1788                         TreeElement *nten = ten->next, *par;
1789                         tselem = TREESTORE(ten);
1790                         lib = (Library *)tselem->id;
1791                         if (lib && lib->parent) {
1792                                 par = (TreeElement *)lib->parent->id.newid;
1793                                 if (tselem->id->tag & LIB_TAG_INDIRECT) {
1794                                         /* Only remove from 'first level' if lib is not also directly used. */
1795                                         BLI_remlink(&soops->tree, ten);
1796                                         BLI_addtail(&par->subtree, ten);
1797                                         ten->parent = par;
1798                                 }
1799                                 else {
1800                                         /* Else, make a new copy of the libtree for our parent. */
1801                                         TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0);
1802                                         outliner_add_library_contents(mainvar, soops, dupten, lib);
1803                                         dupten->parent = par;
1804                                 }
1805                         }
1806                         ten = nten;
1807                 }
1808                 /* restore newid pointers */
1809                 for (lib = mainvar->library.first; lib; lib = lib->id.next)
1810                         lib->id.newid = NULL;
1811                 
1812         }
1813         else if (soops->outlinevis == SO_ALL_SCENES) {
1814                 Scene *sce;
1815                 for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
1816                         te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
1817                         tselem = TREESTORE(te);
1818                         if (sce == scene && show_opened)
1819                                 tselem->flag &= ~TSE_CLOSED;
1820
1821                         FOREACH_SCENE_OBJECT(scene, ob)
1822                         {
1823                                 outliner_add_element(soops, &te->subtree, ob, te, 0, 0);
1824                         }
1825                         FOREACH_SCENE_OBJECT_END
1826
1827                         outliner_make_hierarchy(&te->subtree);
1828
1829                         /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1830                         FOREACH_SCENE_OBJECT(scene, ob)
1831                         {
1832                                 ob->id.newid = NULL;
1833                         }
1834                         FOREACH_SCENE_OBJECT_END
1835                 }
1836         }
1837         else if (soops->outlinevis == SO_CUR_SCENE) {
1838                 
1839                 outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
1840
1841                 FOREACH_SCENE_OBJECT(scene, ob)
1842                 {
1843                         outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
1844                 }
1845                 FOREACH_SCENE_OBJECT_END
1846                 outliner_make_hierarchy(&soops->tree);
1847         }
1848         else if (soops->outlinevis == SO_VISIBLE) {
1849                 FOREACH_VISIBLE_BASE(sl, base)
1850                 {
1851                         ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1852                         ten->directdata = base;
1853
1854                 }
1855                 FOREACH_VISIBLE_BASE_END
1856                 outliner_make_hierarchy(&soops->tree);
1857         }
1858         else if (soops->outlinevis == SO_GROUPS) {
1859                 Group *group;
1860                 GroupObject *go;
1861                 
1862                 for (group = mainvar->group.first; group; group = group->id.next) {
1863                         if (group->gobject.first) {
1864                                 te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
1865                                 
1866                                 for (go = group->gobject.first; go; go = go->next) {
1867                                         outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
1868                                 }
1869                                 outliner_make_hierarchy(&te->subtree);
1870                                 /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
1871                                 for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
1872                         }
1873                 }
1874         }
1875         else if (soops->outlinevis == SO_SAME_TYPE) {
1876                 Object *ob_active = OBACT_NEW(sl);
1877                 if (ob_active) {
1878                         FOREACH_SCENE_OBJECT(scene, ob)
1879                         {
1880                                 if (ob->type == ob_active->type) {
1881                                         outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0);
1882                                 }
1883                         }
1884                         FOREACH_SCENE_OBJECT_END
1885                         outliner_make_hierarchy(&soops->tree);
1886                 }
1887         }
1888         else if (soops->outlinevis == SO_SELECTED) {
1889                 FOREACH_SELECTED_BASE(sl, base)
1890                 {
1891                         ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
1892                         ten->directdata = base;
1893                 }
1894                 FOREACH_SELECTED_BASE_END
1895                 outliner_make_hierarchy(&soops->tree);
1896         }
1897         else if (soops->outlinevis == SO_SEQUENCE) {
1898                 Sequence *seq;
1899                 Editing *ed = BKE_sequencer_editing_get(scene, false);
1900                 int op;
1901
1902                 if (ed == NULL)
1903                         return;
1904
1905                 seq = ed->seqbasep->first;
1906                 if (!seq)
1907                         return;
1908
1909                 while (seq) {
1910                         op = need_add_seq_dup(seq);
1911                         if (op == 1) {
1912                                 /* ten = */ outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE, 0);
1913                         }
1914                         else if (op == 0) {
1915                                 ten = outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0);
1916                                 outliner_add_seq_dup(soops, seq, ten, 0);
1917                         }
1918                         seq = seq->next;
1919                 }
1920         }
1921         else if (soops->outlinevis == SO_DATABLOCKS) {
1922                 PointerRNA mainptr;
1923
1924                 RNA_main_pointer_create(mainvar, &mainptr);
1925
1926                 ten = outliner_add_element(soops, &soops->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1);
1927
1928                 if (show_opened) {
1929                         tselem = TREESTORE(ten);
1930                         tselem->flag &= ~TSE_CLOSED;
1931                 }
1932         }
1933         else if (soops->outlinevis == SO_USERDEF) {
1934                 PointerRNA userdefptr;
1935
1936                 RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr);
1937
1938                 ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
1939
1940                 if (show_opened) {
1941                         tselem = TREESTORE(ten);
1942                         tselem->flag &= ~TSE_CLOSED;
1943                 }
1944         }
1945         else if (soops->outlinevis == SO_ID_ORPHANS) {
1946                 outliner_add_orphaned_datablocks(mainvar, soops);
1947         }
1948         else if (soops->outlinevis == SO_ACT_LAYER) {
1949                 outliner_add_collections_act_layer(soops, sl);
1950         }
1951         else if (soops->outlinevis == SO_COLLECTIONS) {
1952                 outliner_add_collections_master(soops, scene);
1953         }
1954         else {
1955                 ten = outliner_add_element(soops, &soops->tree, OBACT_NEW(sl), NULL, 0, 0);
1956                 ten->directdata = BASACT_NEW(sl);
1957         }
1958
1959         if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
1960                 outliner_sort(&soops->tree);
1961         }
1962         outliner_filter_tree(soops, &soops->tree);
1963
1964         BKE_main_id_clear_newpoins(mainvar);
1965 }
1966
1967