Projet

Général

Profil

Paste
Télécharger (135 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / panelizer / plugins / entity / PanelizerEntityDefault.class.php @ 136a805a

1
<?php
2
/**
3
 * @file
4
 * Base class for the Panelizer Entity plugin.
5
 */
6

    
7
/**
8
 * Interface to describe how PanelizerEntity plugin objects are implemented.
9
 */
10
interface PanelizerEntityInterface {
11
  /**
12
   * Initialize the plugin object.
13
   */
14
  public function init($plugin);
15

    
16
  // Public Drupal hooks
17
  public function hook_menu(&$items);
18
  public function hook_menu_alter(&$items);
19
  public function hook_form_alter(&$form, &$form_state, $form_id);
20
  public function hook_permission(&$items);
21
  public function hook_admin_paths(&$items);
22
  public function hook_views_data_alter(&$data);
23

    
24
  // Entity specific Drupal hooks
25
  public function hook_entity_load(&$entities);
26
  public function hook_entity_insert($entity);
27
  public function hook_entity_update($entity);
28
  public function hook_entity_delete($entity);
29
  public function hook_field_attach_delete_revision($entity);
30

    
31
  /**
32
   * Check if the necessary Page Manager display is enabled and the appropriate
33
   * variant has not been disabled.
34
   *
35
   * @return boolean
36
   *   Whether or not both the Page Manager display and the variant are enabled.
37
   */
38
  public function check_page_manager_status();
39

    
40
  /**
41
   * Add entity specific form to the Panelizer settings form.
42
   *
43
   * This is primarily to allow bundle selection per entity type.
44
   */
45
  public function settings_form(&$form, &$form_state);
46

    
47
  /**
48
   * Validate entity specific settings on the Panelizer settings form.
49
   */
50
  public function settings_form_validate(&$form, &$form_state);
51

    
52
  /**
53
   * Submit entity specific settings on the Panelizer settings form.
54
   */
55
  public function settings_form_submit(&$form, &$form_state);
56

    
57
  /**
58
   * Load the named default panel for the bundle.
59
   */
60
  public function get_default_panelizer_object($bundle, $name);
61

    
62
  /**
63
   * Determine if the current user has access to the $panelizer.
64
   */
65
  public function access_default_panelizer_object($panelizer);
66

    
67
  /**
68
   * Determine if a bundle is panelized
69
   */
70
  public function is_panelized($bundle);
71

    
72
  /**
73
   * Determine if a bundle has a defalt panel
74
   */
75
  public function has_default_panel($bundle);
76

    
77
  /**
78
   * Determine if a bundle is allowed choices.
79
   */
80
  public function has_panel_choice($bundle);
81

    
82
  /**
83
   * Determine the default name for the default object.
84
   */
85
  public function get_default_display_default_name($bundle, $view_mode = 'page_manager');
86

    
87
  /**
88
   * Determine the variable name used to identify the default display for the
89
   * given bundle/view mode combination.
90
   */
91
  public function get_default_display_variable_name($bundle, $view_mode = 'page_manager');
92

    
93
  /**
94
   * Determine the default display name for a given bundle & view mode
95
   * combination.
96
   */
97
  public function get_default_display_name($bundle, $view_mode = 'page_manager');
98

    
99
  /**
100
   * Determine whether a specific default display object exists.
101
   */
102
  public function default_display_exists($display_name);
103

    
104
  /**
105
   * Get a default display for a newly panelized entity.
106
   *
107
   * This is meant to give administrators a starting point when panelizing
108
   * new entities.
109
   */
110
  function get_default_display($bundle, $view_mode);
111

    
112
  /**
113
   * Identify the view modes that are available for use with this entity bundle.
114
   *
115
   * @param string $bundle
116
   *   The entity bundle to check. Defaults to '0', which will check for view
117
   *   modes that are available by default for all entities.
118
   *
119
   * @return array
120
   *   A list of view modes that are available to be panelized.
121
   */
122
  public function get_available_view_modes($bundle = 0);
123

    
124
  /**
125
   * Identify the view modes that are enabled for use with Panelizer.
126
   *
127
   * @param string $bundle
128
   *   The entity bundle to check.
129
   *
130
   * @return array
131
   *   A list of view modes that are panelized.
132
   */
133
  public function get_enabled_view_modes($bundle);
134

    
135
  /**
136
   * Get a panelizer object for the key.
137
   *
138
   * This must be implemented for each entity type, as the default object
139
   * implements a special case for handling panelizer defaults.
140
   */
141
   // @todo this seems to be unused now.
142
//  function get_panelizer_object($key);
143

    
144
  /**
145
   * Render a panelized entity.
146
   */
147
  function render_entity($entity, $view_mode, $langcode = NULL, $args = array(), $address = NULL);
148

    
149
  /**
150
   * Fetch an object array of CTools contexts from panelizer information.
151
   */
152
  public function get_contexts($panelizer, $entity = NULL);
153

    
154
  /**
155
   * Callback to get the base context for a panelized entity
156
   */
157
  public function get_base_contexts($entity = NULL);
158

    
159
  /**
160
   * Confirm the view mode to be used, check if a substitute is assigned,
161
   * failover to 'default'.
162
   *
163
   * @param string $view_mode
164
   *   The original view mode to be checked.
165
   * @param string $bundle
166
   *   The entity bundle being used.
167
   *
168
   * @return string
169
   *   The final view mode that will be used.
170
   */
171
  public function get_view_mode($view_mode, $bundle);
172

    
173
  /**
174
   * Obtain the machine name of the Page Manager task.
175
   *
176
   * @return string
177
   *   The machine name for the Page Manager task; returns FALSE if this
178
   *   entity does not support Page Manager.
179
   */
180
  public function get_page_manager_task_name();
181

    
182
  /**
183
   * Identifies a substitute view mode for a given bundle.
184
   *
185
   * @param string $view_mode
186
   *   The original view mode to be checked.
187
   * @param string $bundle
188
   *   The entity bundle being checked.
189
   *
190
   * @return string
191
   *   The view mode that will be used.
192
   */
193
  public function get_substitute($view_mode, $bundle);
194

    
195
  /**
196
   * Obtain the system path to an entity bundle's display settings page for a
197
   * specific view mode.
198
   *
199
   * @param string $bundle
200
   * @param string $view_mode
201
   *
202
   * @return string
203
   *   The system path of the display settings page for this bundle/view mode
204
   *   combination.
205
   */
206
  public function admin_bundle_display_path($bundle, $view_mode);
207

    
208
  /**
209
   * Determine if the current user has $op access on the $entity.
210
   */
211
  public function entity_access($op, $entity);
212

    
213
  /**
214
   * Implement the save function for the entity.
215
   */
216
  public function entity_save($entity);
217

    
218
  /**
219
   * Determine if an entity allows revisions and whether or not the current
220
   * user has access to control that.
221
   *
222
   * @param $entity
223
   *   The entity in question.
224
   * @return
225
   *   An array. The first parameter is a boolean as to whether or not the
226
   *   entity supports revisions, the second parameter is whether or not the
227
   *   user can control if a revision is created, the third states whether or
228
   *   not the revision is created by default.
229
   */
230
  public function entity_allows_revisions($entity);
231

    
232
  /**
233
   * Get the visible identifier of the identity.
234
   *
235
   * This is overridable because it can be a bit awkward using the
236
   * default label.
237
   *
238
   * @return
239
   *   A translated, safe string.
240
   */
241
  public function entity_identifier($entity);
242

    
243
  /**
244
   * Get the name of bundles on the entity.
245
   *
246
   * Entity API doesn't give us a way to determine this, so the class must
247
   * do this.
248
   *
249
   * @return
250
   *   A translated, safe string.
251
   */
252
  public function entity_bundle_label();
253

    
254
  /**
255
   * Fetch the entity out of a build for hook_entity_view.
256
   *
257
   * @param $build
258
   *   The render array that contains the entity.
259
   */
260
  public function get_entity_view_entity($build);
261

    
262
  /**
263
   * Identify whether page manager is enabled for this entity type.
264
   *
265
   * @return bool
266
   */
267
  public function is_page_manager_enabled();
268
}
269

    
270
/**
271
 * Base class for the Panelizer Entity plugin.
272
 */
273
abstract class PanelizerEntityDefault implements PanelizerEntityInterface {
274
  /**
275
   * Where in the entity admin UI we should add Panelizer tabs with bundles.
276
   */
277
  public $entity_admin_root = NULL;
278

    
279
  /**
280
   * True if the entity supports revisions.
281
   */
282
  public $supports_revisions = FALSE;
283

    
284
  /**
285
   * The base table in SQL the entity uses, for views support.
286
   */
287
  public $views_table = '';
288

    
289
  /**
290
   * The plugin metadata.
291
   */
292
  public $plugin = NULL;
293

    
294
  /**
295
   * The entity type the plugin is for. This is from the $plugin array.
296
   */
297
  public $entity_type = '';
298

    
299
  /**
300
   * Storage for the display defaults already loaded by the system. Used in
301
   * default_display_exists().
302
   */
303
  private $displays = array();
304
  private $displays_loaded = array();
305

    
306
  /**
307
   *
308
   */
309
  private $enabled_view_modes = array();
310

    
311
  /**
312
   * Initialize the plugin and store the plugin info.
313
   */
314
  function init($plugin) {
315
    $this->plugin = $plugin;
316
    $this->entity_type = $plugin['name'];
317
  }
318

    
319
  /**
320
   * Implements a delegated hook_permission.
321
   */
322
  public function hook_permission(&$items) {
323
    $entity_info = entity_get_info($this->entity_type);
324
    // Make a permission for each bundle we control.
325
    foreach ($this->plugin['bundles'] as $bundle => $settings) {
326
      // This is before the if because it shows up regardless of whether
327
      // or not a type is panelized.
328
      $items["administer panelizer $this->entity_type $bundle defaults"] = array(
329
        'title' => t('%entity_name %bundle_name: Administer Panelizer default panels, allowed content and settings.', array(
330
          '%entity_name' => $entity_info['label'],
331
          '%bundle_name' => $entity_info['bundles'][$bundle]['label'],
332
        )),
333
        'description' => t('Users with this permission can fully administer panelizer for this entity bundle.'),
334
      );
335

    
336
      if (empty($settings['status'])) {
337
        continue;
338
      }
339

    
340
      $items["administer panelizer $this->entity_type $bundle overview"] = array(
341
        'title' => t('%entity_name %bundle_name: Administer Panelizer overview', array(
342
          '%entity_name' => $entity_info['label'],
343
          '%bundle_name' => $entity_info['bundles'][$bundle]['label'],
344
        )),
345
        'description' => t('Allow access to the panelizer overview page for the entity type/bundle. Note: This permission will be required for panelizer tabs to appear on an entity.'),
346
      );
347
      foreach (panelizer_operations() as $path => $operation) {
348
        $items["administer panelizer $this->entity_type $bundle $path"] = array(
349
          'title' => t('%entity_name %bundle_name: Administer Panelizer @operation', array(
350
            '%entity_name' => $entity_info['label'],
351
            '%bundle_name' => $entity_info['bundles'][$bundle]['label'],
352
            '@operation' => $operation['link title'],
353
          )),
354
        );
355
      }
356

    
357
      // Account for the choice permission when dealing with view modes.
358
      foreach ($settings['view modes'] as $view_mode => $view_mode_settings) {
359
        if (!empty($view_mode_settings['choice'])) {
360
          $items["administer panelizer $this->entity_type $bundle choice"] = array(
361
            'title' => t('%entity_name %bundle_name: Choose panels', array(
362
              '%entity_name' => $entity_info['label'],
363
              '%bundle_name' => $entity_info['bundles'][$bundle]['label'],
364
            )),
365
            'description' => t('Allows the user to choose which default display the entity uses.'),
366
          );
367
          // Break out of loop after finding one we just need to see if we should
368
          // enable the permission.
369
          break;
370
        }
371
      }
372
    }
373
  }
374

    
375
  /**
376
   * Implements a delegated hook_menu.
377
   */
378
  public function hook_menu(&$items) {
379
    if (!empty($this->plugin['entity path'])) {
380
      // Figure out where in the path the entity will be.
381
      $bits = explode('/', $this->plugin['entity path']);
382
      foreach ($bits as $count => $bit) {
383
        if (strpos($bit, '%') === 0) {
384
          $position = $count;
385
          break;
386
        }
387
      }
388

    
389
      if (!isset($position)) {
390
        return;
391
      }
392

    
393
      $total = count($bits);
394

    
395
      // Configure entity editing pages
396
      $base = array(
397
        'access callback' => 'panelizer_entity_plugin_callback_switcher',
398
        'access arguments' => array($this->entity_type, 'access', 'admin', $position, 'overview'),
399
        'page callback' => 'panelizer_entity_plugin_switcher_page',
400
        'type' => MENU_LOCAL_TASK,
401
      );
402

    
403
      $items[$this->plugin['entity path'] . '/panelizer'] = array(
404
        'title' => 'Customize display',
405
        // make sure this is accessible to panelize entities with no defaults.
406
        'page arguments' => array($this->entity_type, 'overview', $position),
407
        'weight' => 11,
408
        'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
409
      ) + $base;
410

    
411
      $items[$this->plugin['entity path'] . '/panelizer/overview'] = array(
412
        'title' => 'Overview',
413
        'page arguments' => array($this->entity_type, 'overview', $position),
414
        'type' => MENU_DEFAULT_LOCAL_TASK,
415
        'weight' => -10,
416
      ) + $base;
417

    
418
      if ($this->supports_revisions) {
419
        $rev_base = $base;
420
        $rev_base['load arguments'] = array($position + 2);
421
        $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer'] = array(
422
          'title' => 'Customize display',
423
          // Make sure this is accessible to panelize entities with no defaults.
424
          'page arguments' => array($this->entity_type, 'overview', $position),
425
          'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
426
          'type' => MENU_LOCAL_TASK,
427
          'weight' => 11,
428
        ) + $rev_base;
429

    
430
        // Integration with Workbench Moderation.
431
        if (module_exists('workbench_moderation') && $this->entity_type == 'node') {
432
          $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer']['type'] = MENU_CALLBACK;
433
        }
434

    
435
        $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/overview'] = array(
436
          'title' => 'Overview',
437
          'page arguments' => array($this->entity_type, 'overview', $position),
438
          'type' => MENU_DEFAULT_LOCAL_TASK,
439
          'weight' => -100,
440
        ) + $rev_base;
441
      }
442

    
443
      // Put in all of our view mode based paths.
444
      $weight = 0;
445
      foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
446
        $items[$this->plugin['entity path'] . "/panelizer/$view_mode"] = array(
447
          'title' => $view_mode_info['label'],
448
          'page arguments' => array($this->entity_type, 'settings', $position, $view_mode),
449
          'access arguments' => array($this->entity_type, 'access', 'admin', $position, 'settings', $view_mode),
450
          'weight' => $weight++,
451
        ) + $base;
452

    
453
        if ($this->supports_revisions) {
454
          $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/' . $view_mode] = array(
455
            'title' => $view_mode_info['label'],
456
            'page arguments' => array($this->entity_type, 'content', $position, $view_mode),
457
            'access arguments' => array($this->entity_type, 'access', 'admin', $position, 'content', $view_mode),
458
            'weight' => $weight++,
459
          ) + $base;
460
        }
461

    
462
        foreach (panelizer_operations() as $path => $operation) {
463
          $items[$this->plugin['entity path'] . '/panelizer/' . $view_mode . '/' . $path] = array(
464
            'title' => $operation['menu title'],
465
            'page arguments' => array($this->entity_type, $path, $position, $view_mode),
466
            'access arguments' => array($this->entity_type, 'access', 'admin', $position, $path, $view_mode),
467
            'weight' => $weight++,
468
          ) + $base;
469
          if (isset($operation['file'])) {
470
            $items[$this->plugin['entity path'] . '/panelizer/' . $view_mode . '/' . $path]['file'] = $operation['file'];
471
          }
472
          if (isset($operation['file path'])) {
473
            $items[$this->plugin['entity path'] . '/panelizer/' . $view_mode . '/' . $path]['file path'] = $operation['file path'];
474
          }
475
        }
476

    
477
        // Add our special reset item:
478
        $items[$this->plugin['entity path'] . '/panelizer/' . $view_mode . '/reset'] = array(
479
          'title' => t('Reset to Defaults'),
480
          'page arguments' => array($this->entity_type, 'reset', $position, $view_mode),
481
          'type' => MENU_CALLBACK,
482
        ) + $base;
483

    
484
        if ($this->supports_revisions) {
485
          $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/' . $view_mode . '/' . $path] = array(
486
            'title' => $operation['menu title'],
487
            'page arguments' => array($this->entity_type, $path, $position, $view_mode),
488
            'access arguments' => array($this->entity_type, 'access', 'admin', $position, $path, $view_mode),
489
            'weight' => $weight++,
490
          ) + $rev_base;
491

    
492
          if (isset($operation['file'])) {
493
            $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/' . $view_mode . '/' . $path]['file'] = $operation['file'];
494
          }
495
          if (isset($operation['file path'])) {
496
            $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/' . $view_mode . '/' . $path]['file path'] = $operation['file path'];
497
          }
498
        }
499

    
500
        // Make the 'content' URLs the local default tasks.
501
        $items[$this->plugin['entity path'] . '/panelizer/' . $view_mode . '/content']['type'] = MENU_DEFAULT_LOCAL_TASK;
502
        if ($this->supports_revisions && isset($items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/' . $view_mode . '/content']['type'])) {
503
          $items[$this->plugin['entity path'] . '/revisions/%panelizer_node_revision/panelizer/' . $view_mode . '/content']['type'] = MENU_DEFAULT_LOCAL_TASK;
504
        }
505
      }
506
    }
507

    
508
    if (!empty($items)) {
509
      ksort($items);
510
    }
511

    
512
    // Also add administrative links to the bundle.
513
    if (!empty($this->entity_admin_root)) {
514
      $this->add_admin_links($this->entity_admin_root, $this->entity_admin_bundle, $items);
515
    }
516
  }
517

    
518
  /**
519
   * Helper function to add administrative menu items into an entity's already existing structure.
520
   *
521
   * While this very closely follows the administrative items placed into the
522
   * menu in admin.inc, it is a little bit different because of how bundles
523
   * are placed into the URL. So the code is close but not QUITE reusable
524
   * without going through some hoops.
525
   *
526
   * @param $root
527
   *   The root path. This will be something like 'admin/structure/types/manage/%'.
528
   *   Everything will be placed at $root/panelizer/*.
529
   * @param $bundle
530
   *   This is either the numeric position of the bundle or, for entity types
531
   *   that do not support bundles, a hard coded bundle string.
532
   * @param &$items
533
   *   The array of menu items this is being added to.
534
   */
535
  public function add_admin_links($root, $bundle, &$items) {
536
    // Node $root = 'admin/structure/types/manage/%
537
    // Taxonomy $root = 'admin/structure/taxonomy/%'
538
    // User $root = 'admin/config/people/accounts'
539
    $parts = explode('/', $root);
540
    $base_count = count($parts);
541

    
542
    // Configure settings pages.
543
    $settings_base = array(
544
      'access callback' => 'panelizer_is_panelized',
545
      'access arguments' => array($this->entity_type, $bundle),
546
      'file' => 'includes/admin.inc',
547
    );
548

    
549
    // This is the base tab that will be added. The weight is set
550
    // to try and make sure it stays to the right of manage fields
551
    // and manage display.
552
    $items[$root . '/panelizer'] = array(
553
      'title' => 'Panelizer',
554
      'page callback' => 'panelizer_allowed_content_page',
555
      'page arguments' => array($this->entity_type, $bundle),
556
      'type' => MENU_LOCAL_TASK,
557
      'weight' => 5,
558
    ) + $settings_base;
559

    
560
    $items[$root . '/panelizer/allowed'] = array(
561
      'title' => 'Allowed content',
562
      'page callback' => 'panelizer_allowed_content_page',
563
      'page arguments' => array($this->entity_type, $bundle),
564
      'type' => MENU_DEFAULT_LOCAL_TASK,
565
      'weight' => -10,
566
    ) + $settings_base;
567

    
568
    $weight = 1;
569
    foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
570
      $tabs_base = array(
571
        'access callback' => 'panelizer_has_no_choice_callback',
572
        'access arguments' => array($this->entity_type, $bundle, $view_mode),
573
        'page arguments' => array($this->entity_type, $bundle, 'default', $view_mode),
574
        'type' => MENU_LOCAL_TASK,
575
        'file' => 'includes/admin.inc',
576
        'weight' => $weight++,
577
      );
578

    
579
      $items[$root . '/panelizer/' . $view_mode] = array(
580
        'access callback' => 'panelizer_is_panelized',
581
        'title' => $view_mode_info['label'],
582
        'page callback' => 'panelizer_default_list_or_settings_page',
583
      ) + $tabs_base;
584

    
585
      $index = 0;
586
      foreach (panelizer_operations() as $path => $operation) {
587
        $items[$root . '/panelizer/' . $view_mode . '/' . $path] = array(
588
          'title' => $operation['menu title'],
589
          'page callback' => $operation['admin callback'],
590
          // Use the index to keep them in the proper order.
591
          'weight' => $index - 4,
592
          'type' => ($index === 0) ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
593
        ) + $tabs_base;
594
        if (isset($operation['file'])) {
595
          $items[$root . '/panelizer/' . $view_mode . '/' . $path]['file'] = $operation['file'];
596
        }
597
        if (isset($operation['file path'])) {
598
          $items[$root . '/panelizer/' . $view_mode . '/' . $path]['file path'] = $operation['file path'];
599
        }
600
        $index++;
601
      }
602

    
603
      $subtabs_base = array(
604
        'access callback' => 'panelizer_administer_panelizer_default',
605
        'access arguments' => array($this->entity_type, $bundle, $base_count + 2, $base_count + 1),
606
        'page arguments' => array($this->entity_type, $bundle, $base_count + 2, $base_count + 1),
607
        'type' => MENU_LOCAL_TASK,
608
        'file' => 'includes/admin.inc',
609
      );
610

    
611
      $items[$root . '/panelizer/' . $view_mode . '/%'] = array(
612
        'title' => 'Settings',
613
        'page callback' => 'panelizer_default_settings_page',
614
        'title callback' => 'panelizer_default_name_title_callback',
615
        'type' => MENU_CALLBACK,
616
      ) + $subtabs_base;
617

    
618
      $index = 0;
619
      foreach (panelizer_operations() as $path => $operation) {
620
        $items[$root . '/panelizer/' . $view_mode . '/%/' . $path] = array(
621
          'title' => $operation['menu title'],
622
          'page callback' => $operation['admin callback'],
623
          // Use the index to keep them in the proper order.
624
          'weight' => $index - 4,
625
        ) + $subtabs_base;
626
        if (isset($operation['file'])) {
627
          $items[$root . '/panelizer/' . $view_mode . '/%/' . $path]['file'] = $operation['file'];
628
        }
629
        if (isset($operation['file path'])) {
630
          $items[$root . '/panelizer/' . $view_mode . '/%/' . $path]['file path'] = $operation['file path'];
631
        }
632
        $index++;
633
      }
634

    
635
      // This special tab isn't a normal operation because appears only
636
      // in the admin menu.
637
      $items[$root . '/panelizer/' . $view_mode . '/%/access'] = array(
638
        'title' => 'Access',
639
        'page callback' => 'panelizer_default_access_page',
640
        'weight' => -2,
641
      ) + $subtabs_base;
642

    
643
      // Also make clones of all the export UI menu items. Again there is some
644
      // duplicated code here because of subtle differences.
645
      // Load the $plugin information.
646
      ctools_include('export-ui');
647
      $plugin = ctools_get_export_ui('panelizer_defaults');
648

    
649
      $ui_items = $plugin['menu']['items'];
650

    
651
      // Change the item to a tab.
652
      $ui_items['list']['type'] = MENU_LOCAL_TASK;
653
      $ui_items['list']['weight'] = -6;
654
      $ui_items['list']['title'] = 'List';
655

    
656
      // Menu local actions are weird.
657
      if (isset($ui_items['add']['path'])) {
658
        $ui_items['add']['path'] = 'list/add';
659
      }
660
      if (isset($ui_items['import']['path'])) {
661
        $ui_items['import']['path'] = 'list/import';
662
      }
663

    
664
      // Edit is being handled elsewhere.
665
      unset($ui_items['edit callback']);
666
      unset($ui_items['access']);
667
      unset($ui_items['list callback']);
668
      foreach (panelizer_operations() as $path => $operation) {
669
        $location = isset($operation['ui path']) ? $operation['ui path'] : $path;
670
        if (isset($ui_items[$location])) {
671
          unset($ui_items[$location]);
672
        }
673
      }
674

    
675
      // Change the callbacks for everything.
676
      foreach ($ui_items as $key => $item) {
677
        // originally admin/config/content/panelizer/%panelizer_handler
678
        $ui_items[$key]['access callback'] = 'panelizer_has_choice_callback_view_mode';
679
        $ui_items[$key]['access arguments'] = array($this->entity_type, $bundle, $view_mode);
680
        $ui_items[$key]['page callback'] = 'panelizer_default_list_or_settings_page';
681
        $ui_items[$key]['page arguments'][0] = $view_mode;
682
        array_unshift($ui_items[$key]['page arguments'], '');
683
        array_unshift($ui_items[$key]['page arguments'], $bundle);
684
        array_unshift($ui_items[$key]['page arguments'], $this->entity_type);
685
        $ui_items[$key]['path'] = str_replace('list/', '', $ui_items[$key]['path']);
686

    
687
        // Some of the page arguments attempt to pass the eight argument (item
688
        // #7, starting at 0) to the callback in order to work on the display
689
        // object. However, for some entities this will end up being the $op
690
        // instead of the object name, e.g. 'clone' instead of
691
        // 'taxonomy_term:tags:default'.
692
        if (!empty($ui_items[$key]['page arguments'][5]) && is_numeric($bundle)) {
693
          $ui_items[$key]['page arguments'][5] = $bundle + 3;
694
        }
695
      }
696

    
697
      foreach ($ui_items as $item) {
698
        // Add menu item defaults.
699
        $item += array(
700
          'file' => 'export-ui.inc',
701
          'file path' => drupal_get_path('module', 'ctools') . '/includes',
702
        );
703

    
704
        $path = !empty($item['path']) ? $root . '/panelizer/' . $view_mode . '/' . $item['path'] : $root . '/panelizer/' . $view_mode;
705
        unset($item['path']);
706
        $items[$path] = $item;
707
      }
708
    }
709
  }
710

    
711
  /**
712
   * Identify the view modes that are available for use with this entity bundle.
713
   *
714
   * @param string $bundle
715
   *   The entity bundle to identify. Defaults to '0', a placeholder for all
716
   *   bundles on this entity.
717
   *
718
   * @return array
719
   *   A list of view modes that are available to be panelized.
720
   */
721
  public function get_available_view_modes($bundle = 0) {
722
    if (!isset($this->enabled_view_modes[$bundle])) {
723
      $view_modes = array();
724
      $entity_info = entity_get_info($this->entity_type);
725
      $bundle_info = array();
726
      $view_mode_settings = array();
727
      if (!empty($bundle)) {
728
        $view_mode_settings = field_view_mode_settings($this->entity_type, $bundle);
729

    
730
        if (isset($entity_info['bundles'][$bundle])) {
731
          $bundle_info = $entity_info['bundles'][$bundle];
732
        }
733
      }
734

    
735
      foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
736
        // Automatically allow view modes that are part of Panels.
737
        if (isset($entity_info['view modes'][$view_mode])) {
738
          // Skip this view mode if it isn't enabled for this bundle.
739
          if (!empty($bundle)) {
740
            if (empty($view_mode_settings[$view_mode]['custom_settings'])) {
741
              continue;
742
            }
743
          }
744
          // When configuring a new bundle for an entity, the view modes that are by
745
          // default set to now have custom settings will be hidden, to avoid
746
          // confusion.
747
          else {
748
            if (isset($entity_info['view modes'][$view_mode]['custom settings']) && empty($entity_info['view modes'][$view_mode]['custom settings'])) {
749
              continue;
750
            }
751
          }
752
        }
753
        $this->enabled_view_modes[$bundle][$view_mode] = $view_mode_info['label'];
754
      }
755
    }
756

    
757
    return $this->enabled_view_modes[$bundle];
758
  }
759

    
760
  /**
761
   * Identify the view modes that are enabled for use with Panelizer.
762
   *
763
   * @param string $bundle
764
   *   The entity bundle to identify. Defaults to '0', a placeholder for all
765
   *   bundles on this entity.
766
   *
767
   * @return array
768
   *   A list of view modes that are panelized.
769
   */
770
  public function get_enabled_view_modes($bundle) {
771
    $enabled = array();
772
    $available = $this->get_available_view_modes($bundle);
773
  }
774

    
775
  /**
776
   * Identify the view mode that will actually be used for a specific request.
777
   *
778
   * @param string $view_mode
779
   *   The original view mode to be checked.
780
   * @param string $bundle
781
   *   The entity bundle being used.
782
   *
783
   * @return string
784
   *   The final view mode that will be used.
785
   */
786
  public function get_view_mode($view_mode, $bundle) {
787
    $settings = !empty($this->plugin['bundles'][$bundle]) ? $this->plugin['bundles'][$bundle] : array('status' => FALSE, 'choice' => FALSE);
788

    
789
    // Test to see if this view mode is actually panelizable at all.
790
    if (!isset($this->plugin['view modes'][$view_mode]) || (empty($this->plugin['view modes'][$view_mode]['custom settings']) && empty($this->plugin['view mode status'][$bundle][$view_mode]))) {
791
      $view_mode = 'default';
792
    }
793

    
794
    // See if a substitute should be used.
795
    $substitute = $this->get_substitute($view_mode, $bundle);
796
    if (!empty($substitute)) {
797
      $view_mode = $substitute;
798
    }
799

    
800
    return $view_mode;
801
  }
802

    
803
  /**
804
   * Obtain the machine name of the Page Manager task.
805
   *
806
   * @return string
807
   *   The machine name for the Page Manager task; returns FALSE if this
808
   *   entity does not support Page Manager.
809
   */
810
  public function get_page_manager_task_name() {
811
    if (empty($this->plugin['uses page manager'])) {
812
      return FALSE;
813
    }
814
    else {
815
      return $this->entity_type . '_view';
816
    }
817
  }
818

    
819
  /**
820
   * Identifies a substitute view mode for a given bundle.
821
   *
822
   * @param string $view_mode
823
   *   The original view mode to be checked.
824
   * @param string $bundle
825
   *   The entity bundle being checked.
826
   *
827
   * @return string
828
   *   The view mode that will be used.
829
   */
830
  public function get_substitute($view_mode, $bundle) {
831
    $substitute = '';
832

    
833
    // See if a substitute should be used.
834
    $settings = !empty($this->plugin['bundles'][$bundle]) ? $this->plugin['bundles'][$bundle] : array('status' => FALSE, 'choice' => FALSE);
835
    if (!empty($settings['view modes'][$view_mode]['substitute'])) {
836
      $substitute = $settings['view modes'][$view_mode]['substitute'];
837
    }
838

    
839
    return $substitute;
840
  }
841

    
842
  /**
843
   * Obtain the system path to an entity bundle's display settings page for a
844
   * specific view mode.
845
   *
846
   * @param string $bundle
847
   * @param string $view_mode
848
   *
849
   * @return string
850
   *   The system path of the display settings page for this bundle/view mode
851
   *   combination.
852
   */
853
  public function admin_bundle_display_path($bundle, $view_mode) {
854
    $path = $this->entity_admin_root;
855

    
856
    $pos = strpos($path, '%');
857
    if ($pos !== FALSE) {
858
      $path = substr($path, 0, $pos) . $bundle;
859
    }
860

    
861
    $path .= '/display';
862
    if ($view_mode != 'default') {
863
      $path .= '/' . $view_mode;
864
    }
865

    
866
    return $path;
867
  }
868

    
869
  /**
870
   * Check if the necessary Page Manager display is enabled and the appropriate
871
   * variant has not been disabled.
872
   *
873
   * @return boolean
874
   *   Whether or not both the Page Manager display and the variant are enabled.
875
   */
876
  public function check_page_manager_status() {
877
    $pm_links = array(
878
      '!pm' => l('Page Manager', 'admin/structure/pages'),
879
      '!panels' => l('Panels', 'admin/structure/panels'),
880
      '!task_name' => $this->get_page_manager_task_name(),
881
      '!entity_type' => $this->entity_type,
882
    );
883

    
884
    // The display in Page Manager must be enabled.
885
    if ($this->is_page_manager_enabled()) {
886
      drupal_set_message(t('Note: "!task_name" display must be enabled in !pm in order for the !entity_type full page display ("Full page override") to work correctly.', $pm_links), 'warning', FALSE);
887
      return FALSE;
888
    }
889
    // The Panelizer variant must also be enabled.
890
    else {
891
      $task = page_manager_get_task($pm_links['!task_name']);
892
      $handler = page_manager_load_task_handler($task, '', 'term_view_panelizer');
893
      if (!empty($handler->disabled)) {
894
        drupal_set_message(t('The "Panelizer" variant on the "!task_name" display is currently not enabled in !pm. This must be enabled for Panelizer to be able to display !entity_types using the "Full page override" view mode.', $pm_links), 'warning', FALSE);
895
        return FALSE;
896
      }
897
    }
898

    
899
    return TRUE;
900
  }
901

    
902
  /**
903
   * Add the panelizer settings form to a single entity bundle config form.
904
   *
905
   * @param &$form
906
   *   The form array.
907
   * @param &$form_state
908
   *   The form state array.
909
   * @param $bundle
910
   *   The machine name of the bundle this form is for.
911
   * @param $type_location
912
   *   The location in the form state values that the bundle name will be;
913
   *   this is used so that if a machine name of a bundle is changed, Panelizer
914
   *   can update as much as possible.
915
   */
916
  public function add_bundle_setting_form(&$form, &$form_state, $bundle, $type_location) {
917
    $settings = !empty($this->plugin['bundles'][$bundle]) ? $this->plugin['bundles'][$bundle] : array('status' => FALSE, 'choice' => FALSE);
918
    $entity_info = entity_get_info($this->entity_type);
919
    $perms_url = url('admin/people/permissions');
920
    $manage_display = t('Manage Display');
921
    $bundle_info = array();
922
    if (isset($entity_info['bundles'][$bundle])) {
923
      $bundle_info = $entity_info['bundles'][$bundle];
924
      if (!empty($bundle_info['admin']['real path'])) {
925
        $manage_display = l($manage_display, $bundle_info['admin']['real path'] . '/display');
926
      }
927
    }
928
    $view_mode_settings = array();
929
    if (!empty($bundle)) {
930
      $view_mode_settings = field_view_mode_settings($this->entity_type, $bundle);
931
    }
932

    
933
    $form['panelizer'] = array(
934
      '#type' => 'fieldset',
935
      '#title' => t('Panelizer'),
936
      '#collapsible' => TRUE,
937
      '#collapsed' => FALSE,
938
      '#group' => 'additional_settings',
939
      '#attributes' => array(
940
        'class' => array('panelizer-entity-bundle'),
941
      ),
942
      '#bundle' => $bundle,
943
      '#location' => $type_location,
944
      '#tree' => TRUE,
945
      '#access' => panelizer_administer_entity_bundle($this, $bundle),
946
      '#attached' => array(
947
        'js' => array(ctools_attach_js('panelizer-entity-bundle', 'panelizer')),
948
      ),
949
    );
950

    
951
    // The master checkbox.
952
    $form['panelizer']['status'] = array(
953
      '#title' => t('Panelize'),
954
      '#type' => 'checkbox',
955
      '#default_value' => !empty($settings['status']),
956
      '#id' => 'panelizer-status',
957
      '#description' => t('Allow content of this type to have its display controlled by Panelizer. Once enabled, each individual view mode will have further options and will add <a href="!perm_url">several new permissions</a>.', array('!perm_url' => $perms_url)) . '<br />'
958
        . t('Other than "Full page override" and "Default", only view modes enabled through the Custom Display Settings section of the !manage_display tab will be available for use.', array('!manage_display' => $manage_display)) . '<br />'
959
        . t('Once enabled, a new tab named "Customize display" will show on pages for this content.'),
960
    );
961

    
962
    // Help, I need somebody.
963
    $form['panelizer']['help'] = array(
964
      '#title' => t('Optional help message to show above the display selector, if applicable'),
965
      '#type' => 'textarea',
966
      '#rows' => 3,
967
      '#default_value' => !empty($settings['help']) ? $settings['help'] : '',
968
      '#id' => 'panelizer-help',
969
      '#description' => t('Only used if one or more of the view modes has a display that allows multiple values and the "Customize display" tab is to be shown on the entity edit form. Allows HTML.'),
970
      '#states' => array(
971
        'visible' => array(
972
          '#panelizer-status' => array('checked' => TRUE),
973
        ),
974
      ),
975
    );
976

    
977
    $view_modes = $this->get_available_view_modes($bundle);
978
    foreach ($view_modes as $view_mode => $view_mode_label) {
979
      $view_mode_info = $this->plugin['view modes'][$view_mode];
980

    
981
      $form['panelizer']['view modes'][$view_mode] = array(
982
        '#type' => 'item',
983
        // '#title' => '<hr />' . $view_mode_info['label'],
984
        '#states' => array(
985
          'visible' => array(
986
            '#panelizer-status' => array('checked' => TRUE),
987
          ),
988
        ),
989
      );
990

    
991
      // Show the optional view mode description.
992
      $pm_links = array(
993
        '!pm' => l('Page Manager', 'admin/structure/pages'),
994
        '!panels' => l('Panels', 'admin/structure/panels'),
995
        '!entity_type' => $this->entity_type,
996
        '!task_name' => $this->get_page_manager_task_name(),
997
      );
998

    
999
      $description = '';
1000
      if ($view_mode == 'default') {
1001
        $description = t('If a requested view mode for an entity was not enabled in the !manage_display tab page, this view mode will be used as a failover. For example, if "Teaser" was being used but it was not enabled.', array('!manage_display' => $manage_display));
1002
      }
1003
      elseif ($view_mode == 'page_manager') {
1004
        $description = t("A custom view mode only used when !pm/!panels is used to control this entity's full page display, i.e. the '!task_name' display is enabled. Unlike the \"!full\" view mode, this one allows customization of the page title.",
1005
          $pm_links + array(
1006
            '!full' => !empty($entity_info['view modes']['full']['label']) ? $entity_info['view modes']['full']['label'] : 'Full',
1007
          ));
1008
      }
1009
      elseif ($view_mode == 'full') {
1010
        $description = t('Used when viewing !entity_type entities on their standalone page, does not allow customization of the page title.', array('!entity_type' => $this->entity_type));
1011
      }
1012
      elseif ($view_mode == 'teaser') {
1013
        $description = t('Used in content lists by default, e.g. on the default homepage and on taxonomy term pages.');
1014
      }
1015
      elseif ($view_mode == 'rss') {
1016
        $description = t('Used by the default RSS content lists.');
1017
      }
1018
      $form['panelizer']['view modes'][$view_mode]['status'] = array(
1019
        '#title' => $view_mode_info['label'],
1020
        '#type' => 'checkbox',
1021
        '#default_value' => !empty($settings['view modes'][$view_mode]['status']),
1022
        '#id' => 'panelizer-' . $view_mode . '-status',
1023
        '#prefix' => '<hr />',
1024
        '#description' => $description,
1025
        '#attributes' => array(
1026
          'title' => $view_mode_info['label'],
1027
        ),
1028
        '#states' => array(
1029
          'visible' => array(
1030
            '#panelizer-status' => array('checked' => TRUE),
1031
          ),
1032
        ),
1033
      );
1034
      if ($view_mode == 'page_manager') {
1035
        if (!$this->is_page_manager_enabled()) {
1036
          $form['panelizer']['view modes'][$view_mode]['status']['#title'] .= ' (<em>'
1037
            . t('!pm is enabled correctly', $pm_links)
1038
            . '</em>)';
1039
        }
1040
        else {
1041
          $form['panelizer']['view modes'][$view_mode]['status']['#title'] .= ' (<em>'
1042
            . t('"!task_name" must be enabled in !pm', $pm_links)
1043
            . '</em>)';
1044
          // Only display this message if the form has not been submitted, the
1045
          // bundle has been panelized and the view mode is panelized.
1046
          if (empty($form_state['input']) && !empty($settings['status']) && !empty($settings['view modes'][$view_mode]['status'])) {
1047
            drupal_set_message(t('Note: "!task_name" display must be enabled in !pm in order for the !entity_type full page display ("Full page override") to work correctly.', $pm_links), 'warning', FALSE);
1048
          }
1049
        }
1050
      }
1051

    
1052
      $options = array('' => t('- Ignore this option -')) + $view_modes;
1053
      unset($options[$view_mode]);
1054
      $form['panelizer']['view modes'][$view_mode]['substitute'] = array(
1055
        '#title' => t('Substitute a different view mode in place of this one'),
1056
        '#description' => t("Allows this view mode to be enabled but for the actual display to be handled by another view mode. This can save on configuration effort should multiple view modes need to look the same."),
1057
        '#type' => 'select',
1058
        '#options' => $options,
1059
        '#default_value' => $this->get_substitute($view_mode, $bundle),
1060
        '#id' => 'panelizer-' . $view_mode . '-substitute',
1061
        '#states' => array(
1062
          'visible' => array(
1063
            '#panelizer-status' => array('checked' => TRUE),
1064
            '#panelizer-' . $view_mode . '-status' => array('checked' => TRUE),
1065
          ),
1066
        ),
1067
      );
1068

    
1069
      $form['panelizer']['view modes'][$view_mode]['default'] = array(
1070
        '#title' => t('Provide an initial display named "Default"'),
1071
        '#type' => 'checkbox',
1072
        '#default_value' => !empty($settings['view modes'][$view_mode]['status']) && !empty($settings['view modes'][$view_mode]['default']),
1073
        '#id' => 'panelizer-' . $view_mode . '-initial',
1074
        '#states' => array(
1075
          'visible' => array(
1076
            '#panelizer-status' => array('checked' => TRUE),
1077
            '#panelizer-' . $view_mode . '-status' => array('checked' => TRUE),
1078
            '#panelizer-' . $view_mode . '-substitute' => array('value' => ''),
1079
          ),
1080
        ),
1081
      );
1082

    
1083
      // Obtain a list of all available panels for this view mode / bundle.
1084
      $panelizers = $this->get_default_panelizer_objects($bundle . '.' . $view_mode);
1085
      $options = array();
1086
      if (!empty($panelizers)) {
1087
        foreach ($panelizers as $name => $panelizer) {
1088
          // Don't show disabled displays.
1089
          if (empty($panelizer->disabled)) {
1090
            $options[$name] = $panelizer->title;
1091
          }
1092
        }
1093
      }
1094
      if (!empty($options)) {
1095
        ksort($options);
1096
      }
1097

    
1098
      // The default display to be used if nothing found.
1099
      $default_name = implode(':', array($this->entity_type, $bundle, 'default'));
1100
      $variable_name = 'panelizer_' . $this->entity_type . ':' . $bundle . ':' . $view_mode . '_selection';
1101
      if ($view_mode != 'page_manager') {
1102
        $default_name .= ':' . $view_mode;
1103
      }
1104
      // If this has not been set previously, use the 'default' as the default
1105
      // selection.
1106
      $default_value = variable_get($variable_name, FALSE);
1107
      if (empty($default_value)) {
1108
        $default_value = $default_name;
1109
      }
1110
      // Indicate which item is actually the default.
1111
      if (count($options) > 1 && isset($options[$default_value])) {
1112
        $options[$default_value] .= ' (' . t('default') . ')';
1113
      }
1114

    
1115
      if (!empty($bundle_info) && count($options) > 0) {
1116
        $form['panelizer']['view modes'][$view_mode]['selection'] = array(
1117
          '#title' => t('Default panel'),
1118
          '#type' => 'select',
1119
          '#options' => $options,
1120
          '#default_value' => $default_value,
1121
          '#id' => 'panelizer-' . $view_mode . '-default',
1122
          '#states' => array(
1123
            'visible' => array(
1124
              '#panelizer-status' => array('checked' => TRUE),
1125
              '#panelizer-' . $view_mode . '-status' => array('checked' => TRUE),
1126
              '#panelizer-' . $view_mode . '-substitute' => array('value' => ''),
1127
            ),
1128
          ),
1129
          '#required' => count($options),
1130
          '#disabled' => count($options) == 0,
1131
          '#description' => t('The default display to be used for new %bundle records. If "Allow panel choice" is not enabled, the item selected will be used for any new %bundle record. All existing %bundle records will have to be manually updated to the new selection.', array('%bundle' => $bundle)),
1132
        );
1133

    
1134
        $form['panelizer']['view modes'][$view_mode]['default revert'] = array(
1135
          '#type' => 'checkbox',
1136
          '#title' => t('Update existing entities to use this display'),
1137
          '#states' => array(
1138
            'visible' => array(
1139
              '#panelizer-status' => array('checked' => TRUE),
1140
              '#panelizer-' . $view_mode . '-status' => array('checked' => TRUE),
1141
              '#panelizer-' . $view_mode . '-substitute' => array('value' => ''),
1142
            ),
1143
          ),
1144
          '#description' => t('Will update all %bundle records to use the newly selected display, unless they have been customized. Note: only takes effect when the display is changed, and will not work if the default was not assigned previously.', array('%bundle' => $bundle)),
1145
          '#field_prefix' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
1146
        );
1147
      }
1148

    
1149
      // Control whether the default can be selected.
1150
      $form['panelizer']['view modes'][$view_mode]['choice'] = array(
1151
        '#title' => t('Allow per-record display choice'),
1152
        '#type' => 'checkbox',
1153
        '#default_value' => !empty($settings['view modes'][$view_mode]['status']) && !empty($settings['view modes'][$view_mode]['choice']),
1154
        '#id' => 'panelizer-' . $view_mode . '-choice',
1155
        '#states' => array(
1156
          'visible' => array(
1157
            '#panelizer-status' => array('checked' => TRUE),
1158
            '#panelizer-' . $view_mode . '-status' => array('checked' => TRUE),
1159
            '#panelizer-' . $view_mode . '-substitute' => array('value' => ''),
1160
          ),
1161
        ),
1162
        '#description' => t("Allows multiple displays to be created for this view mode. Once created, a selector will be provided on the %bundle record's edit form allowing the display of this view mode to be chosen. Additionally, any customizations made will be based upon the selected display. Note: the selector will not be shown if there is only one display, instead the default will be automatically selected.", array('%bundle' => $bundle)),
1163
      );
1164
      if (!empty($bundle)) {
1165
        $form['panelizer']['view modes'][$view_mode]['choice']['#description'] .= '<br />'
1166
          . t('This option adds a <a href="!perm_url">new permission</a>: !perm',
1167
            array(
1168
              '!perm_url' => $perms_url,
1169
              '!perm' => t('%entity_name %bundle_name: Choose panels',
1170
                array(
1171
                  '%entity_name' => $entity_info['label'],
1172
                  '%bundle_name' => $entity_info['bundles'][$bundle]['label'],
1173
                )
1174
              ),
1175
            )
1176
          );
1177
      }
1178
    }
1179

    
1180
    array_unshift($form['#submit'], 'panelizer_entity_default_bundle_form_submit');
1181

    
1182
    $form_state['panelizer_entity_handler'] = $this;
1183
  }
1184

    
1185
  /**
1186
   * Submit callback for the bundle edit form.
1187
   */
1188
  public function add_bundle_setting_form_submit($form, &$form_state, $bundle, $type_location) {
1189
    // Some types do not support changing bundles, so we don't check if it's
1190
    // not possible to change.
1191
    if ($type_location) {
1192
      $new_bundle = drupal_array_get_nested_value($form_state['values'], $type_location);
1193
    }
1194
    else {
1195
      $new_bundle = $bundle;
1196
    }
1197

    
1198
    // Check to see if the bundle has changed. If so, we need to move stuff
1199
    // around.
1200
    if ($bundle && $new_bundle != $bundle) {
1201
      // Remove old settings.
1202
      variable_del('panelizer_defaults_' . $this->entity_type . '_' . $bundle);
1203
      $allowed_layouts = variable_get('panelizer_' . $this->entity_type . ':' . $bundle . '_allowed_layouts', NULL);
1204
      if ($allowed_layouts) {
1205
        variable_del('panelizer_' . $this->entity_type . ':' . $bundle . '_allowed_layouts');
1206
        variable_set('panelizer_' . $this->entity_type . ':' . $new_bundle . '_allowed_layouts', $allowed_layouts);
1207
      }
1208
      $default = variable_get('panelizer_' . $this->entity_type . ':' . $bundle . '_default', NULL);
1209
      if ($default) {
1210
        variable_del('panelizer_' . $this->entity_type . ':' . $bundle . '_default');
1211
        variable_set('panelizer_' . $this->entity_type . ':' . $new_bundle . '_default', $default);
1212
      }
1213

    
1214
      // Load up all panelizer defaults for the old bundle and resave them
1215
      // for the new bundle.
1216
      $panelizer_defaults = $this->get_default_panelizer_objects($bundle);
1217
      if (!empty($panelizer_defaults)) {
1218
        foreach ($panelizer_defaults as $panelizer) {
1219
          list($entity_type, $old_bundle, $name) = explode(':', $panelizer->name);
1220
          $panelizer->name = implode(':', array($entity_type, $new_bundle, $name));
1221
          if ($panelizer->view_mode != 'page_manager') {
1222
            $panelizer->name .= ':' . $panelizer->view_mode;
1223
          }
1224

    
1225
          // The default display selection.
1226
          $old_variable_name = 'panelizer_' . $this->entity_type . ':' . $bundle . ':' . $panelizer->view_mode . '_selection';
1227
          $new_variable_name = 'panelizer_' . $this->entity_type . ':' . $new_bundle . ':' . $panelizer->view_mode . '_selection';
1228
          $default_layout = variable_get($old_variable_name, NULL);
1229
          if (!is_null($default_layout)) {
1230
            variable_set($new_variable_name, $default_layout);
1231
            variable_del($old_variable_name);
1232
          }
1233

    
1234
          $panelizer->panelizer_key = $new_bundle;
1235
          // If there's a pnid this should change the name and retain the pnid.
1236
          // If there is no pnid this will create a new one in the database
1237
          // because exported panelizer defaults attached to a bundle will have
1238
          // to be moved to the database in order to follow along and then be
1239
          // re-exported.
1240
          // @todo Should we warn the user about this?
1241
          ctools_export_crud_save('panelizer_defaults', $panelizer);
1242
        }
1243
      }
1244
    }
1245

    
1246
    // Fix the configuration.
1247
    // If the main configuration is disabled then everything gets disabled.
1248
    if (empty($form_state['values']['panelizer']['status'])) {
1249
      $form_state['values']['panelizer']['view modes'] = array();
1250
    }
1251
    elseif (!empty($form_state['values']['panelizer']['view modes'])) {
1252
      // Make sure each setting is disabled if the view mode is disabled.
1253
      foreach ($form_state['values']['panelizer']['view modes'] as $view_mode => &$config) {
1254
        if (empty($config['status'])) {
1255
          foreach ($config as $key => $val) {
1256
            $config[$key] = 0;
1257
          }
1258
        }
1259
      }
1260
    }
1261

    
1262
    // Save the default display for this bundle to a variable so that it may be
1263
    // controlled separately.
1264
    foreach ($this->get_default_panelizer_objects($new_bundle) as $panelizer) {
1265
      if (isset($form_state['values']['panelizer']['view modes'][$panelizer->view_mode]['selection'])) {
1266
        $variable_name = 'panelizer_' . $this->entity_type . ':' . $new_bundle . ':' . $panelizer->view_mode . '_selection';
1267
        $old_value = variable_get($variable_name, NULL);
1268
        $new_value = $form_state['values']['panelizer']['view modes'][$panelizer->view_mode]['selection'];
1269

    
1270
        // Save the variable.
1271
        variable_set($variable_name, $new_value);
1272

    
1273
        // Cleanup.
1274

    
1275
        // Additional cleanup if the default display was changed.
1276
        if (!is_null($old_value) && $old_value != $new_value) {
1277
          // The user specifically requested that existing entities are to be
1278
          // updated to the new display.
1279
          if (!empty($form_state['values']['panelizer']['view modes'][$panelizer->view_mode]['default revert'])) {
1280
            $updated_count = db_update('panelizer_entity')
1281
              ->fields(array('name' => $new_value))
1282
              ->condition('name', $old_value)
1283
              ->execute();
1284
            drupal_set_message(t('@count @entity records were updated to the new Panelizer display for the @mode view mode.', array('@count' => $updated_count, '@entity' => $this->entity_type, '@mode' => $panelizer->view_mode)));
1285

    
1286
            // If EntityCache is enabled, clear all records of this type. This
1287
            // is a little heavy-handed, but I don't believe there's an easy way
1288
            // to clear only entities of certain types without querying for them
1289
            // first, which could trigger an execution timeout.
1290
            if (module_exists('entitycache')) {
1291
              cache_clear_all('*', 'cache_entity_' . $this->entity_type, TRUE);
1292
            }
1293
          }
1294
        }
1295
      }
1296
    }
1297

    
1298
    // Remove some settings that shouldn't be saved with the others.
1299
    if (!empty($form_state['values']['panelizer']['view modes'])) {
1300
      foreach ($form_state['values']['panelizer']['view modes'] as $view_mode => $settings) {
1301
        unset($form_state['values']['panelizer']['view modes'][$view_mode]['selection']);
1302
        unset($form_state['values']['panelizer']['view modes'][$view_mode]['default revert']);
1303
      }
1304
    }
1305

    
1306
    variable_set('panelizer_defaults_' . $this->entity_type . '_' . $new_bundle, $form_state['values']['panelizer']);
1307

    
1308
    // Verify the necessary Page Manager prerequisites are ready.
1309
    if (!empty($form_state['values']['panelizer']['status'])
1310
      && !empty($form_state['values']['panelizer']['view modes']['page_manager']['status'])
1311
      && $this->is_page_manager_enabled()) {
1312
      $this->check_page_manager_status();
1313
    }
1314

    
1315
    // Unset this so that the type save forms don't try to save it to variables.
1316
    unset($form_state['values']['panelizer']);
1317
  }
1318

    
1319
  /**
1320
   * Implements a delegated hook_menu.
1321
   */
1322
  public function hook_admin_paths(&$items) {
1323
    if (!empty($this->plugin['entity path'])) {
1324
      $bits = explode('/', $this->plugin['entity path']);
1325
      foreach ($bits as $count => $bit) {
1326
        if (strpos($bit, '%') === 0) {
1327
          $bits[$count] = '*';
1328
        }
1329
      }
1330

    
1331
      $path = implode('/', $bits);
1332
      $items[$path . '/panelizer*'] = TRUE;
1333
    }
1334
  }
1335

    
1336
  public function hook_menu_alter(&$items) {
1337

    
1338
  }
1339

    
1340
  public function hook_form_alter(&$form, &$form_state, $form_id) {
1341

    
1342
  }
1343

    
1344
  public function get_default_display_default_name($bundle, $view_mode = 'page_manager') {
1345
    $default_name = implode(':', array($this->entity_type, $bundle, 'default'));
1346

    
1347
    if ($view_mode != 'page_manager') {
1348
      $default_name .= ':' . $view_mode;
1349
    }
1350

    
1351
    return $default_name;
1352
  }
1353

    
1354
  public function get_default_display_name($bundle, $view_mode = 'page_manager') {
1355
    $variable_name = $this->get_default_display_variable_name($bundle, $view_mode);
1356
    // If this has not been set previously, use the 'default' as the default
1357
    // selection.
1358
    $default_value = variable_get($variable_name, FALSE);
1359

    
1360
    if (empty($default_value)) {
1361
      $default_value = $this->get_default_display_default_name($bundle, $view_mode);
1362
    }
1363

    
1364
    return $default_value;
1365
  }
1366

    
1367
  public function default_display_exists($display_name) {
1368
    // If the display name is empty then the display doesn't exist.
1369
    if (empty($display_name)) {
1370
      return FALSE;
1371
    }
1372

    
1373
    $parts = explode(':', $display_name);
1374
    // If the display name doesn't contain the entity_type, the bundle and the
1375
    // display machine name, then it's an invalid name.
1376
    if (count($parts) <= 2) {
1377
      return FALSE;
1378
    }
1379

    
1380
    // The entity bundle is the second part of the $display_name string.
1381
    $bundle = $parts[1];
1382

    
1383
    // If no check was performed already to see if displays exist for this
1384
    // bundle, try loading them.
1385
    if (empty($this->displays_loaded[$bundle])) {
1386
      $this->displays_loaded[$bundle] = TRUE;
1387
      $displays = $this->get_default_panelizer_objects($bundle);
1388
      $this->displays = array_merge($this->displays, $displays);
1389
    }
1390

    
1391
    return isset($this->displays[$display_name]);
1392
  }
1393

    
1394
  public function get_default_display_variable_name($bundle, $view_mode = 'page_manager') {
1395
    return 'panelizer_' . $this->entity_type . ':' . $bundle . ':' . $view_mode . '_selection';
1396
  }
1397

    
1398
  // Entity specific Drupal hooks
1399
  public function hook_entity_load(&$entities) {
1400
    ctools_include('export');
1401
    $ids = array();
1402
    $vids = array();
1403
    $bundles = array();
1404

    
1405
    foreach ($entities as $entity) {
1406
      // Don't bother if somehow we've already loaded and are asked to
1407
      // load again.
1408
      if (!empty($entity->panelizer)) {
1409
        continue;
1410
      }
1411

    
1412
      list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1413
      if ($this->is_panelized($bundle)) {
1414
        $ids[] = $entity_id;
1415
        if ($this->supports_revisions) {
1416
          $vids[] = $revision_id;
1417
        }
1418
        $bundles[$entity_id] = $bundle;
1419
      }
1420
    }
1421

    
1422
    if (empty($ids)) {
1423
      return;
1424
    }
1425

    
1426
    // Load all the panelizers associated with the list of entities.
1427
    if ($this->supports_revisions) {
1428
      $result = db_query("SELECT * FROM {panelizer_entity} WHERE entity_type = :entity_type AND revision_id IN (:vids)", array(':entity_type' => $this->entity_type, ':vids' => $vids));
1429
    }
1430
    else {
1431
      $result = db_query("SELECT * FROM {panelizer_entity} WHERE entity_type = :entity_type AND entity_id IN (:ids)", array(':entity_type' => $this->entity_type, ':ids' => $ids));
1432
    }
1433

    
1434
    $panelizers = array();
1435
    while ($panelizer = $result->fetchObject()) {
1436
      $panelizers[$panelizer->entity_id][$panelizer->view_mode] = $panelizer;
1437
    }
1438

    
1439
    $defaults = array();
1440
    $dids = array();
1441

    
1442
    // Go through our entity list and generate a list of defaults and displays
1443
    foreach ($entities as $entity_id => $entity) {
1444
      // Don't bother if somehow we've already loaded and are asked to
1445
      // load again.
1446
      if (!empty($entity->panelizer)) {
1447
        continue;
1448
      }
1449

    
1450
      // Skip not panelized bundles.
1451
      if (empty($bundles[$entity_id])) {
1452
        continue;
1453
      }
1454

    
1455
      // Check for each view mode.
1456
      foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
1457
        // Skip disabled view modes.
1458
        $check_needed = array_key_exists($view_mode, $this->plugin['bundles'][$bundles[$entity_id]]['view modes']);
1459
        $view_mode_disabled = empty($this->plugin['bundles'][$bundles[$entity_id]]['view modes'][$view_mode]['status']);
1460
        if ($check_needed === FALSE || $view_mode_disabled) {
1461
          continue;
1462
        }
1463

    
1464
        // Load the default display for this entity bundle / view_mode.
1465
        $name = $this->get_default_display_name($bundles[$entity_id], $view_mode);
1466

    
1467
        // If no panelizer was loaded for the view mode, queue up defaults.
1468
        if (empty($panelizers[$entity_id][$view_mode]) && $this->has_default_panel($bundles[$entity_id] . '.' . $view_mode)) {
1469
          $defaults[$name] = $name;
1470
        }
1471
        // Otherwise unpack the loaded panelizer.
1472
        else if (!empty($panelizers[$entity_id][$view_mode])) {
1473
          $entity->panelizer[$view_mode] = ctools_export_unpack_object('panelizer_entity', $panelizers[$entity_id][$view_mode]);
1474
          // If somehow we have no name AND no did, fill in the default.
1475
          // This can happen if use of defaults has switched around maybe?
1476
          if (empty($entity->panelizer[$view_mode]->did) && empty($entity->panelizer[$view_mode]->name)) {
1477
            if ($this->has_default_panel($bundles[$entity_id] . '.' . $view_mode)) {
1478
              $entity->panelizer[$view_mode]->name = $name;
1479
            }
1480
            else {
1481
              // With no default, did or name, this doesn't actually exist.
1482
              unset($entity->panelizer[$view_mode]);
1483
              list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1484

    
1485
              db_delete('panelizer_entity')
1486
                ->condition('entity_type', $this->entity_type)
1487
                ->condition('entity_id', $entity_id)
1488
                ->condition('revision_id', $revision_id)
1489
                ->condition('view_mode', $view_mode)
1490
                ->execute();
1491
              continue;
1492
            }
1493
          }
1494

    
1495
          // Panelizers that do not have dids are just a selection of defaults
1496
          // that has never actually been modified.
1497
          if (empty($entity->panelizer[$view_mode]->did) && !empty($entity->panelizer[$view_mode]->name)) {
1498
            $defaults[$entity->panelizer[$view_mode]->name] = $entity->panelizer[$view_mode]->name;
1499
          }
1500
          else {
1501
            $dids[$entity->panelizer[$view_mode]->did] = $entity->panelizer[$view_mode]->did;
1502
          }
1503
        }
1504
      }
1505
    }
1506

    
1507
    // Load any defaults we collected.
1508
    if (!empty($defaults)) {
1509
      $panelizer_defaults = $this->load_default_panelizer_objects($defaults);
1510
    }
1511

    
1512
    // if any panelizers were loaded, get their attached displays.
1513
    if (!empty($dids)) {
1514
      $displays = panels_load_displays($dids);
1515
    }
1516

    
1517
    // Now, go back through our entities and assign dids and defaults
1518
    // accordingly.
1519
    foreach ($entities as $entity_id => $entity) {
1520
      // Skip not panelized bundles.
1521
      if (empty($bundles[$entity_id])) {
1522
        continue;
1523
      }
1524

    
1525
      // Reload these.
1526
      list(, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1527

    
1528
      // Check for each view mode.
1529
      foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
1530
        if (empty($entity->panelizer[$view_mode])) {
1531
          // Load the configured default display.
1532
          $default_value = $this->get_default_display_name($bundle, $view_mode);
1533

    
1534
          if (!empty($panelizer_defaults[$default_value])) {
1535
            $entity->panelizer[$view_mode] = clone $panelizer_defaults[$default_value];
1536
            // Make sure this entity can't write to the default display.
1537
            $entity->panelizer[$view_mode]->did = NULL;
1538
            $entity->panelizer[$view_mode]->entity_id = 0;
1539
            $entity->panelizer[$view_mode]->revision_id = 0;
1540
          }
1541
        }
1542
        elseif (empty($entity->panelizer[$view_mode]->display) || empty($entity->panelizer[$view_mode]->did)) {
1543
          if (!empty($entity->panelizer[$view_mode]->did)) {
1544
            if (empty($displays[$entity->panelizer[$view_mode]->did])) {
1545
              // Somehow the display for this entity has gotten lost?
1546
              $entity->panelizer[$view_mode]->did = NULL;
1547
              $entity->panelizer[$view_mode]->display = $this->get_default_display($bundles[$entity_id], $view_mode);
1548
            }
1549
            else {
1550
              $entity->panelizer[$view_mode]->display = $displays[$entity->panelizer[$view_mode]->did];
1551
            }
1552
          }
1553
          else {
1554
            if (!empty($panelizer_defaults[$entity->panelizer[$view_mode]->name])) {
1555
              // Reload the settings from the default configuration.
1556
              $entity->panelizer[$view_mode] = clone $panelizer_defaults[$entity->panelizer[$view_mode]->name];
1557
              $entity->panelizer[$view_mode]->did = NULL;
1558
              $entity->panelizer[$view_mode]->entity_id = $entity_id;
1559
              $entity->panelizer[$view_mode]->revision_id = $revision_id;
1560
            }
1561
          }
1562
        }
1563
      }
1564
    }
1565
  }
1566

    
1567
  public function hook_entity_insert($entity) {
1568
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1569
    if (!$this->is_panelized($bundle)) {
1570
      return;
1571
    }
1572

    
1573
    // Check to see if this entity is a translation of another entity.
1574
    // If so, use the source entity's panelizer information to clone it.
1575
    if (isset($entity->translation_source) && isset($entity->translation_source->panelizer)) {
1576
      $entity->panelizer = $entity->translation_source->panelizer;
1577
    }
1578

    
1579
    // If there's no panelizer information on the entity then there is nothing to do.
1580
    if (empty($entity->panelizer)) {
1581
      return;
1582
    }
1583

    
1584
    // Allow exports or older data to be deployed successfully.
1585
    if (is_object($entity->panelizer)) {
1586
      $entity->panelizer = array('page_manager' => $entity->panelizer);
1587
    }
1588

    
1589
    foreach ($entity->panelizer as $view_mode => $panelizer) {
1590
      // Don't write out empty records.
1591
      if (empty($panelizer)) {
1592
        continue;
1593
      }
1594

    
1595
      // Just a safety check to make sure we can't have a missing view mode.
1596
      if (empty($view_mode)) {
1597
        $view_mode = 'page_manager';
1598
      }
1599

    
1600
      // In certain circumstances $panelizer will be the default's name rather
1601
      // than a full object.
1602
      if (!is_object($panelizer) && is_array($panelizer) && !empty($panelizer['name'])) {
1603
        $panelizer = $this->get_default_panelizer_object($bundle . '.' . $view_mode, $panelizer['name']);
1604
        $panelizer->did = NULL;
1605

    
1606
        // Ensure original values are maintained.
1607
        $panelizer->entity_id = $entity_id;
1608
        $panelizer->revision_id = $revision_id;
1609
      }
1610

    
1611
      // If this is a default display, skip saving it.
1612
      $default_display = $this->get_default_display_default_name($bundle, $view_mode);
1613
      if (!empty($panelizer->name) && $panelizer->name == $default_display) {
1614
        continue;
1615
      }
1616

    
1617
      // On entity insert, we only write the display if it is not a default.
1618
      // That probably means it came from an export or deploy or something
1619
      // along those lines.
1620
      if (empty($panelizer->name) && !empty($panelizer->display)) {
1621
        // Ensure we don't accidentally overwrite existing display
1622
        // data or anything silly like that.
1623
        $panelizer = $this->clone_panelizer($panelizer, $entity);
1624
        // Ensure that Panels storage is set correctly.
1625
        $panelizer->display->storage_type = 'panelizer_entity';
1626
        $panelizer->display->storage_id = implode(':', array($this->entity_type, $entity_id, $view_mode));
1627
        // First write the display
1628
        panels_save_display($panelizer->display);
1629

    
1630
        // Make sure we have the new did.
1631
        $panelizer->did = $panelizer->display->did;
1632
      }
1633

    
1634
      // To prevent overwriting a cloned entity's $panelizer object, clone it.
1635
      else {
1636
        // Store $panelizer->name as  it is removed by clone_panelizer().
1637
        $stored_name = $panelizer->name;
1638

    
1639
        // Clone the $panelizer object.
1640
        $panelizer = $this->clone_panelizer($panelizer, $entity);
1641

    
1642
        // Restore the original $panelizer->name.
1643
        $panelizer->name = $stored_name;
1644
      }
1645

    
1646
      // Make sure there is a view mode.
1647
      if (empty($panelizer->view_mode)) {
1648
        $panelizer->view_mode = $view_mode;
1649
      }
1650

    
1651
      // And write the new record.
1652
      drupal_write_record('panelizer_entity', $panelizer);
1653
    }
1654
  }
1655

    
1656
  public function hook_entity_update($entity) {
1657
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1658
    if (!$this->is_panelized($bundle)) {
1659
      return;
1660
    }
1661

    
1662
    // If there's no panelizer information on the entity then there is nothing
1663
    // to do.
1664
    if (empty($entity->panelizer)) {
1665
      return;
1666
    }
1667

    
1668
    // Allow exports or older data to be deployed successfully.
1669
    if (is_object($entity->panelizer)) {
1670
      $entity->panelizer = array('page_manager' => $entity->panelizer);
1671
    }
1672

    
1673
    // When updating many/most objects, make sure the previous revision's
1674
    // configuration is loaded too, as they won't be automatically loaded.
1675
    // @todo There may be another way of handling this.
1676
    if (isset($entity->original, $entity->original->panelizer)) {
1677
      foreach ($entity->original->panelizer as $view_mode => $panelizer) {
1678
        if (!isset($entity->panelizer[$view_mode])) {
1679
          $entity->panelizer[$view_mode] = clone $panelizer;
1680
        }
1681
      }
1682
    }
1683

    
1684
    // Update each panelizer configuration.
1685
    foreach ($entity->panelizer as $view_mode => $panelizer) {
1686
      // Don't write out empty records.
1687
      if (empty($panelizer)) {
1688
        continue;
1689
      }
1690

    
1691
      // In some cases $panelizer is array, convert it to an object.
1692
      if (is_array($panelizer)) {
1693
        $panelizer = (object) $panelizer;
1694
      }
1695

    
1696
      // Just a safety check to make sure we can't have a missing view mode.
1697
      if (empty($view_mode)) {
1698
        $view_mode = 'page_manager';
1699
      }
1700

    
1701
      // In certain circumstances $panelizer will be the default's name rather
1702
      // than a full object.
1703
      if (!is_object($panelizer) && is_array($panelizer) && !empty($panelizer['name'])) {
1704
        $panelizer = $this->get_default_panelizer_object($bundle . '.' . $view_mode, $panelizer['name']);
1705
        $panelizer->did = NULL;
1706

    
1707
        // Ensure original values are maintained.
1708
        $panelizer->entity_id = $entity_id;
1709
        $panelizer->revision_id = $revision_id;
1710
      }
1711

    
1712
      // If this is a default display, and a change wasn't made, skip saving it.
1713
      $default_display = $this->get_default_display_default_name($bundle, $view_mode);
1714
      if (empty($panelizer->display_is_modified)
1715
          && !empty($panelizer->name) && $panelizer->name == $default_display) {
1716
        // Delete the existing record for this revision/entity if one existed
1717
        // before and a new revision was not being saved.
1718
        if (empty($entity->revision)) {
1719
          // Only delete the display for this specific revision.
1720
          $this->delete_entity_panelizer($entity, $view_mode, TRUE);
1721
        }
1722
        continue;
1723
      }
1724

    
1725
      // Determine whether an existing Panelizer record needs to be updated or
1726
      // a new one created.
1727
      $update = array();
1728

    
1729
      // This entity supports revisions.
1730
      if ($this->supports_revisions) {
1731
        // If no revision value is assigned, indicating that no record was
1732
        // previously saved for this entity/view_mode combination, or a new
1733
        // revision is being created, create a new {panelizer_entity} record.
1734
        if (empty($panelizer->revision_id) || $panelizer->revision_id != $revision_id) {
1735
          $panelizer->revision_id = $revision_id;
1736
          // If this has a custom display, flag the system that the display
1737
          // needs to be saved as a new record.
1738
          if (!empty($panelizer->did)) {
1739
            $panelizer->display_is_modified = TRUE;
1740
          }
1741
        }
1742
        // This entity is being updated.
1743
        else {
1744
          $update = array('entity_type', 'entity_id', 'revision_id', 'view_mode');
1745
        }
1746
      }
1747
      // This entity does not support revisions.
1748
      else {
1749
        // There is no entity_id set yet, the record was never saved before.
1750
        if (empty($panelizer->entity_id)) {
1751
          // Nothing to do.
1752
        }
1753
        // This record is being updated.
1754
        else {
1755
          $update = array('entity_type', 'entity_id', 'view_mode');
1756
        }
1757
      }
1758

    
1759
      // The editor will set this flag if the display is modified. This lets
1760
      // us know if we need to clone a new display or not.
1761
      // NOTE: This means that when exporting or deploying, we need to be sure
1762
      // to set the display_is_modified flag to ensure this gets written.
1763
      if (!empty($panelizer->display_is_modified)) {
1764
        // Check if this display is shared and avoid changing other revisions
1765
        // displays.
1766
        $has_shared_display_args = array(
1767
          ':entity_type' => $this->entity_type,
1768
          ':entity_id' => $entity_id,
1769
          ':revision_id' => $revision_id,
1770
          ':did' => $panelizer->did,
1771
        );
1772
        $has_shared_display = db_query('SELECT COUNT(did) FROM {panelizer_entity} WHERE entity_type = :entity_type AND entity_id = :entity_id AND revision_id <> :revision_id AND did = :did', $has_shared_display_args)->fetchField();
1773

    
1774
        // If this is a new entry or the entry is using a display from a
1775
        // default, or revision is enabled and this is a shared display, clone
1776
        // the display.
1777
        if (!$update || empty($panelizer->did) || !empty($has_shared_display)) {
1778
          $entity->panelizer[$view_mode] = $panelizer = $this->clone_panelizer($panelizer, $entity);
1779

    
1780
          // Update the cache key since we are adding a new display
1781
          $panelizer->display->cache_key = implode(':', array_filter(array('panelizer', $panelizer->entity_type, $panelizer->entity_id, $view_mode, $revision_id)));
1782
        }
1783

    
1784
        // Ensure that Panels storage is set correctly.
1785
        $panelizer->display->storage_type = 'panelizer_entity';
1786
        $panelizer->display->storage_id = implode(':', array($this->entity_type, $entity_id, $view_mode));
1787

    
1788
        // First write the display.
1789
        panels_save_display($panelizer->display);
1790

    
1791
        // Make sure we have the did.
1792
        $panelizer->did = $panelizer->display->did;
1793

    
1794
        // Ensure that we always write this as NULL when we have our own panel:
1795
        $panelizer->name = NULL;
1796
      }
1797
      else {
1798
        $panelizer->entity_type = $this->entity_type;
1799
        $panelizer->entity_id = $entity_id;
1800
        // The (int) ensures that entities that do not support revisions work
1801
        // since the revision_id cannot be NULL.
1802
        $panelizer->revision_id = (int) $revision_id;
1803

    
1804
        // Make sure we keep the same did as the original if the layout wasn't
1805
        // changed.
1806
        if (empty($panelizer->name) && empty($panelizer->did) && !empty($entity->original->panelizer[$view_mode]->did)) {
1807
          $panelizer->did = $entity->original->panelizer[$view_mode]->did;
1808
          $update = array('entity_type', 'entity_id', 'revision_id', 'view_mode');
1809
        }
1810
      }
1811

    
1812
      // Make sure there is a view mode.
1813
      if (empty($panelizer->view_mode)) {
1814
        $panelizer->view_mode = $view_mode;
1815
      }
1816

    
1817
      // Make sure there is a 'did' value. This can happen when the value is
1818
      // passed via inline_entity_form.
1819
      if (!isset($panelizer->did)) {
1820
        $panelizer->did = 0;
1821
      }
1822

    
1823
      // Save the record.
1824
      drupal_write_record('panelizer_entity', $panelizer, $update);
1825

    
1826
      // If there was a CSS value saved before, update the exported file. This
1827
      // is done after the entity is updated to ensure that the next page load
1828
      // gets the new file.
1829
      ctools_include('css');
1830
      $cache_key = implode(':', array_filter(array('panelizer', $this->entity_type, $entity_id, $view_mode, $revision_id)));
1831
      $filename = ctools_css_retrieve($cache_key);
1832
      if ($filename) {
1833
        ctools_css_clear($cache_key);
1834
      }
1835
      if (!empty($panelizer->css)) {
1836
        ctools_css_store($cache_key, $panelizer->css);
1837
      }
1838
    }
1839
  }
1840

    
1841
  public function hook_entity_delete($entity) {
1842
    $this->delete_entity_panelizer($entity);
1843
  }
1844

    
1845
  public function hook_field_attach_delete_revision($entity) {
1846
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1847

    
1848
    // Locate and delete all displays associated with the entity.
1849
    $revisions = db_query("SELECT revision_id, did FROM {panelizer_entity} WHERE entity_type = :type AND entity_id = :id", array(':type' => (string) $this->entity_type, ':id' => $entity_id))->fetchAllAssoc('revision_id');
1850

    
1851
    // It is possible to have the same did on multiple revisions, if none of
1852
    // those revisions modified the display. Be careful NOT to delete a display
1853
    // that might be in use by another revision.
1854
    $seen = array();
1855
    foreach ($revisions as $info) {
1856
      if ($info->revision_id != $revision_id) {
1857
        $seen[$info->did] = TRUE;
1858
      }
1859
    }
1860

    
1861
    if (!empty($revisions[$revision_id]->did) && empty($seen[$revisions[$revision_id]->did])) {
1862
      panels_delete_display($revisions[$revision_id]->did);
1863
    }
1864

    
1865
    db_delete('panelizer_entity')
1866
      ->condition('entity_type', $this->entity_type)
1867
      ->condition('entity_id', $entity_id)
1868
      ->condition('revision_id', $revision_id)
1869
      ->execute();
1870
  }
1871

    
1872
  public function hook_field_attach_form($entity, &$form, &$form_state, $langcode) {
1873
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1874

    
1875
    // We'll store the form array here so that we can tell at the end if we
1876
    // have any and need to add our fieldset.
1877
    $widgets = array();
1878
    // Need to track the number of actual visible widgets because
1879
    // element_get_visible_children doesn't handle nested fields.
1880
    $visible_widgets = 0;
1881

    
1882
    foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
1883
      $view_bundle = $bundle . '.' . $view_mode;
1884

    
1885
      $panelizers = $this->get_default_panelizer_objects($view_bundle);
1886

    
1887
      // Ignore view modes that don't have a choice, have no displays defined,
1888
      // or already have their own custom display set up.
1889
      if (!$this->has_panel_choice($view_bundle) || empty($panelizers) || !empty($entity->panelizer[$view_mode]->did)) {
1890
        continue;
1891
      }
1892

    
1893
      $options = array();
1894
      foreach ($panelizers as $name => $panelizer) {
1895
        if (empty($panelizer->disabled)) {
1896
          $options[$name] = $panelizer->title ? $panelizer->title : t('Default');
1897
        }
1898
      }
1899

    
1900
      // Load the configured default display.
1901
      $default_value = $this->get_default_display_name($bundle, $view_mode);
1902

    
1903
      // The selected value.
1904
      $selected = $default_value;
1905
      if (!empty($entity->panelizer[$view_mode]->name)) {
1906
        $selected = $entity->panelizer[$view_mode]->name;
1907
      }
1908

    
1909
      // Only display the selector if options were available.
1910
      if (!empty($options)) {
1911
        // Indicate which item is the default.
1912
        if (isset($options[$default_value])) {
1913
          $options[$default_value] .= ' (' . t("default for '@bundle'", array('@bundle' => $bundle)) . ')';
1914
        }
1915

    
1916
        // If only one option is available, don't show the selector.
1917
        if (count($options) === 1) {
1918
          $widgets[$view_mode]['name'] = array(
1919
            '#title' => $view_mode_info['label'],
1920
            '#type' => 'value',
1921
            '#value' => $selected,
1922
            // Put these here because submit does not get a real entity with the
1923
            // actual *(&)ing panelizer.
1924
            '#revision_id' => isset($entity->panelizer[$view_mode]->revision_id) ? $entity->panelizer[$view_mode]->revision_id : NULL,
1925
            '#entity_id' => isset($entity->panelizer[$view_mode]->entity_id) ? $entity->panelizer[$view_mode]->entity_id : NULL,
1926
          );
1927
        }
1928
        else {
1929
          $widgets[$view_mode]['name'] = array(
1930
            '#title' => $view_mode_info['label'],
1931
            '#type' => 'select',
1932
            '#options' => $options,
1933
            '#default_value' => $selected,
1934
            '#required' => TRUE,
1935
            // Put these here because submit does not get a real entity with the
1936
            // actual *(&)ing panelizer.
1937
            '#revision_id' => isset($entity->panelizer[$view_mode]->revision_id) ? $entity->panelizer[$view_mode]->revision_id : NULL,
1938
            '#entity_id' => isset($entity->panelizer[$view_mode]->entity_id) ? $entity->panelizer[$view_mode]->entity_id : NULL,
1939
          );
1940
          $visible_widgets++;
1941
        }
1942
      }
1943
    }
1944

    
1945
    // Only display this if the entity has visible options available.
1946
    if (!empty($widgets)) {
1947
      $form_state['panelizer has choice'] = TRUE;
1948
      $form['panelizer'] = array(
1949
        '#type' => 'fieldset',
1950
        '#access' => $this->panelizer_access('choice', $entity, $view_mode),
1951
        '#title' => t('Customize display'),
1952
        '#collapsible' => TRUE,
1953
        '#collapsed' => TRUE,
1954
        '#group' => 'additional_settings',
1955
        '#attributes' => array(
1956
          'class' => array('panelizer-entity-options'),
1957
        ),
1958
        '#attached' => array(
1959
          'js' => array(ctools_attach_js('panelizer-vertical-tabs', 'panelizer')),
1960
        ),
1961
        '#weight' => -10,
1962
        '#tree' => TRUE,
1963
      ) + $widgets;
1964

    
1965
      // Optional fieldset description.
1966
      if (!empty($this->plugin['bundles'][$bundle]['help'])) {
1967
        $form['panelizer']['#description'] = $this->plugin['bundles'][$bundle]['help'];
1968
      }
1969

    
1970
      // If there are no visible widgets, don't display the fieldset.
1971
      if ($visible_widgets == 0) {
1972
        $form['panelizer']['#access'] = FALSE;
1973
      }
1974
    }
1975
  }
1976

    
1977
  public function hook_field_attach_submit($entity, &$form, &$form_state) {
1978
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
1979
    if (!empty($form_state['panelizer has choice'])) {
1980
      foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
1981
        if (isset($form_state['values']['panelizer'][$view_mode]['name'])) {
1982
          $entity->panelizer[$view_mode] = $this->get_default_panelizer_object($bundle . '.' . $view_mode, $form_state['values']['panelizer'][$view_mode]['name']);
1983
          if (!empty($entity->panelizer[$view_mode])) {
1984
            $entity->panelizer[$view_mode]->did = NULL;
1985

    
1986
            // Ensure original values are maintained, if they exist.
1987
            if (isset($form['panelizer'][$view_mode]['name'])) {
1988
              $entity->panelizer[$view_mode]->entity_id = $form['panelizer'][$view_mode]['name']['#entity_id'];
1989
              $entity->panelizer[$view_mode]->revision_id = $form['panelizer'][$view_mode]['name']['#revision_id'];
1990
            }
1991
          }
1992
        }
1993
      }
1994
    }
1995
  }
1996

    
1997
  /**
1998
   * Determine if the entity allows revisions.
1999
   *
2000
   * @param $entity
2001
   *   The entity to test.
2002
   *
2003
   * @return array
2004
   *   An array. The first parameter is a boolean as to whether or not the
2005
   *   entity supports revisions, the second parameter is whether or not the
2006
   *   user can control if a revision is created, the third states whether or
2007
   *   not the revision is created by default.
2008
   */
2009
  public function entity_allows_revisions($entity) {
2010
    return array(
2011
      // Whether or not the entity supports revisions.
2012
      FALSE,
2013

    
2014
      // Whether or not the user can control if a revision is created.
2015
      FALSE,
2016

    
2017
      // Whether or not the revision is created by default.
2018
      FALSE,
2019
    );
2020
  }
2021

    
2022
  /**
2023
   * Create a new, scrubbed version of a panelizer object.
2024
   */
2025
  public function clone_panelizer($panelizer, $entity) {
2026
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2027
    $panelizer_clone = clone $panelizer;
2028

    
2029
    // In order to ensure we don't actually use and modify the default display,
2030
    // we export and re-import it.
2031
    $code = panels_export_display($panelizer->display);
2032
    ob_start();
2033
    eval($code);
2034
    ob_end_clean();
2035

    
2036
    $panelizer_clone->display = $display;
2037
    $panelizer_clone->did = NULL;
2038
    $panelizer_clone->name = NULL;
2039
    $panelizer_clone->entity_type = $this->entity_type;
2040
    $panelizer_clone->entity_id = $entity_id;
2041
    // The (int) ensures that entities that do not support revisions work
2042
    // since the revision_id cannot be NULL.
2043
    $panelizer_clone->revision_id = (int) $revision_id;
2044

    
2045
    return $panelizer_clone;
2046
  }
2047

    
2048
  function access_admin($entity, $op = NULL, $view_mode = NULL) {
2049
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2050
    if ($view_mode) {
2051
      $bundle .= '.' . $view_mode;
2052
    }
2053
    else {
2054
      $view_mode = 'page_manager';
2055
    }
2056

    
2057
    if (!$this->is_panelized($bundle)) {
2058
      return FALSE;
2059
    }
2060

    
2061
    return $this->panelizer_access($op, $entity, $view_mode) && $this->entity_access('update', $entity);
2062
  }
2063

    
2064
  /**
2065
   * Determine if the user has access to the panelizer operation for this type.
2066
   */
2067
  function panelizer_access($op, $bundle, $view_mode) {
2068
    $og_access = FALSE;
2069
    if (is_object($bundle)) {
2070
      $entity = $bundle;
2071
      list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2072

    
2073
      // Additional support for Organic Groups.
2074
      // @todo move to og_panelizer_access();
2075
      if (module_exists('og')) {
2076
        if (og_is_group($this->entity_type, $entity)) {
2077
          $og_access = og_user_access($this->entity_type, $entity_id, "administer panelizer og_group $op");
2078
        }
2079
        else {
2080
          $og_groups = og_get_entity_groups($this->entity_type, $entity);
2081
          foreach ($og_groups as $og_group_type => $og_gids) {
2082
            foreach ($og_gids as $og_gid) {
2083
              if (og_user_access($og_group_type, $og_gid, "administer panelizer $this->entity_type $bundle $op")) {
2084
                $og_access = TRUE;
2085
              }
2086
            }
2087
          }
2088
        }
2089
      }
2090

    
2091
      // If there is an $op, this must actually be panelized in order to pass.
2092
      // If there is no $op, then the settings page can provide us a "panelize
2093
      // it!" page even if there is no display.
2094
      if ($op && $op != 'overview' && $op != 'settings' && $op != 'choice' && empty($entity->panelizer[$view_mode])) {
2095
        return FALSE;
2096
      }
2097
    }
2098

    
2099
    // Invoke hook_panelizer_access().
2100
    $panelizer_access = module_invoke_all('panelizer_access', $op, $this->entity_type, $bundle, $view_mode);
2101
    array_unshift($panelizer_access, user_access('administer panelizer'), user_access("administer panelizer {$this->entity_type} {$bundle} {$op}"));
2102
    $panelizer_access[] = $og_access;
2103

    
2104
    // Trigger hook_panelizer_access_alter().
2105
    // We can't pass this many parameters to drupal_alter, so stuff them into
2106
    // an array.
2107
    $options = array(
2108
      'op' => $op,
2109
      'entity_type' => $this->entity_type,
2110
      'bundle' => $bundle,
2111
      'view_mode' => $view_mode
2112
    );
2113
    drupal_alter('panelizer_access', $panelizer_access, $options);
2114

    
2115
    foreach ($panelizer_access as $access) {
2116
      if ($access) {
2117
        return $access;
2118
      }
2119
    }
2120
    return FALSE;
2121
  }
2122

    
2123

    
2124
  /**
2125
   * Switched page callback to give the overview page
2126
   */
2127
  function page_overview($js, $input, $entity) {
2128
    $header = array(
2129
      t('View mode'),
2130
      t('Status'),
2131
      t('Operations'),
2132
    );
2133

    
2134
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2135

    
2136
    $rows = array();
2137

    
2138
    $base_url = $this->entity_base_url($entity);
2139

    
2140
    foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
2141
      if (!$this->is_panelized($bundle . '.' . $view_mode)) {
2142
        continue;
2143
      }
2144

    
2145
      $row = array();
2146
      $row[] = $view_mode_info['label'];
2147
      $panelized = TRUE;
2148

    
2149
      if (!empty($entity->panelizer[$view_mode]->name)) {
2150
        ctools_include('export');
2151
        $panelizer = ctools_export_crud_load('panelizer_defaults', $entity->panelizer[$view_mode]->name);
2152
        $status = !empty($panelizer->title) ? check_plain($panelizer->title) : t('Default');
2153
      }
2154
      else if (!empty($entity->panelizer[$view_mode]->did)) {
2155
        $status = t('Custom');
2156
      }
2157
      else {
2158
        $status = t('Not panelized');
2159
        $panelized = FALSE;
2160
      }
2161
      $row[] = $status;
2162

    
2163
      if ($panelized) {
2164
        $links_array = array();
2165
        foreach (panelizer_operations() as $path => $operation) {
2166
          if ($this->panelizer_access($path, $entity, $view_mode)) {
2167
            $links_array[$path] = array(
2168
              'title' => $operation['link title'],
2169
              'href' => $base_url . '/' . $view_mode . '/' . $path,
2170
            );
2171
          }
2172
        }
2173
        if ($status == t('Custom')) {
2174
          $links_array['reset'] = array(
2175
            'title' => t('reset'),
2176
            'href' => $base_url . '/' . $view_mode . '/reset',
2177
          );
2178
        }
2179
      }
2180
      else {
2181
        $links_array = array(
2182
          'panelize' => array(
2183
            'title' => t('panelize'),
2184
            'href' => $base_url . '/' . $view_mode,
2185
          ),
2186
        );
2187
      }
2188

    
2189
      // Allow applications to add additional panelizer tabs.
2190
      $context = array(
2191
        'entity' => $entity,
2192
        'view_mode' => $view_mode,
2193
        'status' => $status,
2194
        'panelized' => $panelized,
2195
      );
2196
      drupal_alter('panelizer_overview_links', $links_array, $this->entity_type, $context);
2197

    
2198
      $links = theme('links', array(
2199
        'links' => $links_array,
2200
        'attributes' => array('class' => array('links', 'inline')),
2201
      ));
2202

    
2203
      $row[] = $links;
2204
      $rows[] = $row;
2205
    }
2206

    
2207
    return array(
2208
      '#theme' => 'table',
2209
      '#header' => $header,
2210
      '#rows' => $rows,
2211
      '#prefix' => '<p>'
2212
        . t('Changes made here will override the default (Panelizer) displays and will only affect this @entity.', array('@entity' => $this->entity_type))
2213
        . "</p>\n",
2214
    );
2215
  }
2216

    
2217
  /**
2218
   * Provides the base panelizer URL for an entity.
2219
   */
2220
  function entity_base_url($entity, $view_mode = NULL) {
2221
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2222

    
2223
    $path_elements[] = $entity_id;
2224

    
2225
    $path = $this->plugin['entity path'];
2226
    if ($this->supports_revisions) {
2227
      $current_entities = entity_load($this->entity_type, array($entity_id));
2228
      $current_entity = array_pop($current_entities);
2229
      if ($revision_id !== $current_entity->vid) {
2230
        $path_elements[] = $revision_id;
2231
        $path .= '/revisions/%';
2232
      }
2233
    }
2234

    
2235
    $bits = explode('/', $path);
2236
    foreach ($bits as $count => $bit) {
2237
      if (strpos($bit, '%') === 0) {
2238
        $bits[$count] = array_shift($path_elements);
2239
      }
2240
    }
2241

    
2242
    $bits[] = 'panelizer';
2243
    if ($view_mode) {
2244
      $bits[] = $view_mode;
2245
    }
2246
    $base_url = implode('/', $bits);
2247

    
2248
    return $base_url;
2249
  }
2250

    
2251
  /**
2252
   * Provides a wrapper for the panelizer page output.
2253
   *
2254
   * Drupal only supports 2 levels of tabs, but we need a 3rd
2255
   * level. We will fake it.
2256
   */
2257
  function wrap_entity_panelizer_pages($entity, $view_mode, $output) {
2258
    $base_url = $this->entity_base_url($entity, $view_mode);
2259
    return $this->make_fake_tabs($base_url, $entity, $view_mode, $output);
2260
  }
2261

    
2262
  /**
2263
   * Provides a wrapper for the panelizer page output.
2264
   *
2265
   * Drupal only supports 2 levels of tabs, but we need a 3rd
2266
   * level. We will fake it.
2267
   */
2268
  function wrap_default_panelizer_pages($bundle, $output) {
2269
    list($bundle, $view_mode) = explode('.', $bundle);
2270
    $base_url = $this->entity_admin_root . '/panelizer/' . $view_mode;
2271
    // We have to sub in the bundle if this is set.
2272
    if (is_numeric($this->entity_admin_bundle)) {
2273
      $bits = explode('/', $base_url);
2274
      $bits[$this->entity_admin_bundle] = $bundle;
2275
      $base_url = implode('/', $bits);
2276
    }
2277

    
2278
    return $this->make_fake_tabs($base_url, $bundle, $view_mode, $output);
2279
  }
2280

    
2281
  /**
2282
   * Create some fake tabs that are attached to a page output.
2283
   */
2284
  function make_fake_tabs($base_url, $bundle, $view_mode, $output) {
2285
    // Integration with Workbench Moderation: these local tabs will be
2286
    // automatically added via the menu system.
2287
    if (module_exists('workbench_moderation') && isset($bundle->workbench_moderation) && $bundle->workbench_moderation['my_revision']->vid == $bundle->workbench_moderation['current']->vid) {
2288
      return $output;
2289
    }
2290

    
2291
    $links_array = array();
2292
    foreach (panelizer_operations() as $path => $operation) {
2293
      if ($this->panelizer_access($path, $bundle, $view_mode)) {
2294
        $links_array[$path] = array(
2295
          'title' => t($operation['menu title']),
2296
          'href' => $base_url . '/' . $path,
2297
        );
2298
      }
2299
    }
2300

    
2301
    // Allow applications to add additional panelizer tabs.
2302
    drupal_alter('panelizer_tab_links', $links_array, $this->entity_type, $bundle, $view_mode);
2303

    
2304
    // Only render if > 1 link, just like core.
2305
    if (count($links_array) <= 1) {
2306
      return $output;
2307
    }
2308

    
2309
    // These fake tabs are pretty despicable, but they'll do.
2310
    $links = '<div class="clearfix">' . theme('links', array(
2311
      'links' => $links_array,
2312
      'attributes' => array('class' => array('tabs', 'secondary')),
2313
    )) . '</div>';
2314

    
2315
    if (is_array($output)) {
2316
      // Use array addition because forms will already be sorted so
2317
      // #weight may not be effective.
2318
      $output = array(
2319
        'panelizer_links' => array(
2320
          '#markup' => $links,
2321
          '#weight' => -10000,
2322
        ),
2323
      ) + $output;
2324
    }
2325
    else {
2326
      $output = $links . $output;
2327
    }
2328

    
2329
    return $output;
2330
  }
2331

    
2332
  /**
2333
   * Switched page callback to give the settings form.
2334
   */
2335
  function page_reset($js, $input, $entity, $view_mode) {
2336
    $panelizer = $entity->panelizer[$view_mode];
2337

    
2338
    $form_state = array(
2339
      'entity' => $entity,
2340
      'revision info' => $this->entity_allows_revisions($entity),
2341
      'panelizer' => $panelizer,
2342
      'view_mode' => $view_mode,
2343
      'no_redirect' => TRUE,
2344
    );
2345

    
2346
    ctools_include('common', 'panelizer');
2347
    $output = drupal_build_form('panelizer_reset_entity_form', $form_state);
2348

    
2349
    if (!empty($form_state['executed'])) {
2350
      $this->reset_entity_panelizer($entity, $view_mode);
2351
      drupal_set_message(t('Panelizer display information has been reset.'));
2352
      drupal_goto(dirname(dirname($_GET['q'])));
2353
    }
2354

    
2355
    return $output;
2356
  }
2357

    
2358
  /**
2359
   * Switched page callback to give the settings form.
2360
   */
2361
  function page_settings($js, $input, $entity, $view_mode) {
2362
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2363

    
2364
    if (empty($entity->panelizer[$view_mode])) {
2365
      // If this entity is not yet panelized, and there is no default panel
2366
      // to do configuration, give them the option of panelizing it.
2367
      if ($this->has_default_panel($bundle . '.' . $view_mode)) {
2368
        return MENU_NOT_FOUND;
2369
      }
2370

    
2371
      // Set the form to the Panelize It! form.
2372
      $form_id = 'panelizer_panelize_entity_form';
2373

    
2374
      // Fetch a special default panelizer that is only accessible with the
2375
      // default_anyway flag.
2376
      $panelizer = $this->get_internal_default_panelizer($bundle, $view_mode);
2377
      $panelizer->name = NULL;
2378
    }
2379
    else {
2380
      $form_id = 'panelizer_settings_form';
2381
      $panelizer = $entity->panelizer[$view_mode];
2382
    }
2383

    
2384
    $form_state = array(
2385
      'entity' => $entity,
2386
      'revision info' => $this->entity_allows_revisions($entity),
2387
      'panelizer' => $panelizer,
2388
      'view_mode' => $view_mode,
2389
      'no_redirect' => TRUE,
2390
    );
2391

    
2392
    ctools_include('common', 'panelizer');
2393
    $output = drupal_build_form($form_id, $form_state);
2394
    if (!empty($form_state['executed'])) {
2395
      $entity->panelizer[$view_mode] = $form_state['panelizer'];
2396

    
2397
      // Make sure that entity_save knows that the panelizer settings are
2398
      // modified and must be made local to the entity.
2399
      if (empty($panelizer->did) || !empty($panelizer->name)) {
2400
        $panelizer->display_is_modified = TRUE;
2401
      }
2402

    
2403
      // Update the entity.
2404
      $this->entity_save($entity);
2405

    
2406
      drupal_set_message(t('The settings have been updated.'));
2407

    
2408
      // Redirect.
2409
      drupal_goto($_GET['q']);
2410
    }
2411

    
2412
    return $this->wrap_entity_panelizer_pages($entity, $view_mode, $output);
2413
  }
2414

    
2415
  function page_context($js, $input, $entity, $view_mode) {
2416
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2417

    
2418
    $cache_key = $entity_id . '.' . $view_mode;
2419
    $panelizer = panelizer_context_cache_get($this->entity_type, $cache_key);
2420

    
2421
    if (empty($panelizer)) {
2422
      return MENU_NOT_FOUND;
2423
    }
2424

    
2425
    $form_state = array(
2426
      'entity' => $entity,
2427
      'revision info' => $this->entity_allows_revisions($entity),
2428
      'panelizer' => &$panelizer,
2429
      'panelizer type' => $this->entity_type,
2430
      'cache key' => $cache_key,
2431
      'no_redirect' => TRUE,
2432
    );
2433

    
2434
    ctools_include('common', 'panelizer');
2435
    $output = drupal_build_form('panelizer_default_context_form', $form_state);
2436
    if (!empty($form_state['executed'])) {
2437
      if (!empty($form_state['clicked_button']['#write'])) {
2438
        $entity->panelizer[$view_mode] = $form_state['panelizer'];
2439

    
2440
        // Make sure that entity_save knows that the panelizer settings are
2441
        // modified and must be made local to the entity.
2442
        if (empty($panelizer->did) || !empty($panelizer->name)) {
2443
          $panelizer->display_is_modified = TRUE;
2444
        }
2445

    
2446
        // Update the entity.
2447
        $this->entity_save($entity);
2448

    
2449
        drupal_set_message(t('The settings have been updated.'));
2450
      }
2451
      else {
2452
        drupal_set_message(t('Changes have been discarded.'));
2453
      }
2454

    
2455
      // Clear the context cache.
2456
      panelizer_context_cache_clear($this->entity_type, $cache_key);
2457

    
2458
      // Redirect.
2459
      drupal_goto($_GET['q']);
2460
    }
2461

    
2462
    return $this->wrap_entity_panelizer_pages($entity, $view_mode, $output);
2463
  }
2464

    
2465
  function page_layout($js, $input, $entity, $view_mode, $step = NULL, $layout = NULL) {
2466
    $panelizer = $entity->panelizer[$view_mode];
2467
    if (empty($panelizer)) {
2468
      return MENU_NOT_FOUND;
2469
    }
2470

    
2471
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2472

    
2473
    $display = $panelizer->display;
2474
    $display->context = $this->get_contexts($panelizer, $entity);
2475

    
2476
    $path = $this->entity_base_url($entity, $view_mode);
2477

    
2478
    $form_state = array(
2479
      'entity' => $entity,
2480
      'revision info' => $this->entity_allows_revisions($entity),
2481
      'display' => $display,
2482
      'wizard path' => $path . '/layout/%step',
2483
      'allowed_layouts' => panelizer_get_allowed_layouts_option($this->entity_type, $bundle),
2484
    );
2485

    
2486
    ctools_include('common', 'panelizer');
2487
    $output = panelizer_change_layout_wizard($form_state, $step, $layout);
2488
    if (!empty($form_state['complete'])) {
2489
      $entity->panelizer[$view_mode]->display = $form_state['display'];
2490
      $entity->panelizer[$view_mode]->display_is_modified = TRUE;
2491
      $this->entity_save($entity);
2492
      drupal_set_message(t('The layout has been changed.'));
2493
      drupal_goto($path . '/content');
2494
    }
2495

    
2496
    return $this->wrap_entity_panelizer_pages($entity, $view_mode, $output);
2497
  }
2498

    
2499
  function page_content($js, $input, $entity, $view_mode) {
2500
    $panelizer = $entity->panelizer[$view_mode];
2501
    if (empty($panelizer)) {
2502
      return MENU_NOT_FOUND;
2503
    }
2504

    
2505
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2506

    
2507
    $form_state = array(
2508
      'entity' => $entity,
2509
      'revision info' => $this->entity_allows_revisions($entity),
2510
      'display cache' => panels_edit_cache_get(implode(':', array_filter(array('panelizer', $this->entity_type, $entity_id, $view_mode, $revision_id)))),
2511
      'no_redirect' => TRUE,
2512
    );
2513

    
2514
    ctools_include('common', 'panelizer');
2515
    $output = drupal_build_form('panelizer_edit_content_form', $form_state);
2516
    if (!empty($form_state['executed'])) {
2517
      if (!empty($form_state['clicked_button']['#save-display'])) {
2518
        drupal_set_message(t('The settings have been updated.'));
2519
        $entity->panelizer[$view_mode]->display = $form_state['display'];
2520
        $entity->panelizer[$view_mode]->display_is_modified = TRUE;
2521
        $this->entity_save($entity);
2522
      }
2523
      else {
2524
        drupal_set_message(t('Changes have been discarded.'));
2525
      }
2526

    
2527
      panels_edit_cache_clear($form_state['display cache']);
2528
      drupal_goto($_GET['q']);
2529
    }
2530

    
2531
    $output = $this->wrap_entity_panelizer_pages($entity, $view_mode, $output);
2532

    
2533
    ctools_set_no_blocks(FALSE);
2534
    drupal_set_page_content($output);
2535
    $page = element_info('page');
2536
    return $page;
2537
  }
2538

    
2539
  /**
2540
   * Delete panelizers associated with the entity.
2541
   *
2542
   * @param object $entity
2543
   *   The entity.
2544
   * @param string $view_mode
2545
   *   The view mode to delete. If not specified, all view modes will be
2546
   *   deleted.
2547
   * @param bool $one_revision
2548
   *   Whether to delete all revisions for this entity, or a specific one.
2549
   */
2550
  function delete_entity_panelizer($entity, $view_mode = NULL, $one_revision = FALSE) {
2551
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2552

    
2553
    // Locate any displays associated with the entity.
2554
    $query = db_select('panelizer_entity', 'pe')
2555
      ->fields('pe', array('did'))
2556
      ->condition('entity_type', $this->entity_type)
2557
      ->condition('entity_id', $entity_id);
2558
    if (!empty($view_mode)) {
2559
      $query->condition('view_mode', $view_mode);
2560
    }
2561
    if (!empty($revision_id) && !empty($one_revision)) {
2562
      $query->condition('revision_id', $revision_id);
2563
    }
2564
    $dids = $query->execute()
2565
      ->fetchCol();
2566

    
2567
    // Delete the Panels displays.
2568
    foreach (array_unique(array_filter($dids)) as $did) {
2569
      panels_delete_display($did);
2570
    }
2571

    
2572
    // Delete the {panelizer_entity} records.
2573
    $delete = db_delete('panelizer_entity')
2574
      ->condition('entity_type', $this->entity_type)
2575
      ->condition('entity_id', $entity_id);
2576
    if (!empty($view_mode)) {
2577
      $delete->condition('view_mode', $view_mode);
2578
    }
2579
    if (!empty($revision_id) && !empty($one_revision)) {
2580
      $delete->condition('revision_id', $revision_id);
2581
    }
2582
    $delete->execute();
2583

    
2584
    // Reset the entity's cache. If the EntityCache module is enabled, this also
2585
    // resets its permanent cache.
2586
    entity_get_controller($this->entity_type)->resetCache(array($entity_id));
2587
  }
2588

    
2589
  /**
2590
   * Reset displays so that the defaults can be used instead.
2591
   *
2592
   * @param object $entity
2593
   *   The entity.
2594
   * @param $view_mode
2595
   *   The view mode to delete. If not specified, all view modes will be
2596
   *   deleted.
2597
   */
2598
  function reset_entity_panelizer($entity, $view_mode = NULL) {
2599
    // Only proceed if the view mode was customized for this entity.
2600
    if (empty($entity->panelizer[$view_mode])) {
2601
      drupal_set_message(t('Unable to reset this view mode'));
2602
    }
2603
    else {
2604
      // Build a list of displays to delete.
2605
      $dids = array();
2606

    
2607
      // Identify this entity's bundle.
2608
      list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
2609

    
2610
      // Add the custom display to the list of displays to delete.
2611
      if (!empty($entity->panelizer[$view_mode]->did)) {
2612
        $dids[] = $entity->panelizer[$view_mode]->did;
2613
      }
2614

    
2615
      // Update the {panelizer_entity} record.
2616
      $entity->panelizer[$view_mode]->did = NULL;
2617
      $entity->panelizer[$view_mode]->name = NULL;
2618

    
2619
      // Update the entity.
2620
      $this->entity_save($entity);
2621

    
2622
      // If a new revision was not created, delete any unused displays.
2623
      if (empty($entity->revision)) {
2624
        // Work out which view modes to use.
2625
        if (!empty($view_mode)) {
2626
          $view_modes = array($view_mode);
2627
        }
2628
        else {
2629
          $entity_info = entity_get_info($this->entity_type);
2630
          $view_modes = array_keys($entity_info['view modes']);
2631
        }
2632

    
2633
        // Locate all displays associated with the entity.
2634
        $new_dids = db_select('panelizer_entity', 'p')
2635
          ->fields('p', array('did'))
2636
          ->condition('entity_type', $this->entity_type)
2637
          ->condition('revision_id', $revision_id)
2638
          ->condition('view_mode', $view_modes, 'IN')
2639
          ->condition('did', '0', '>')
2640
          ->execute()
2641
          ->fetchCol();
2642
        if (!empty($new_dids)) {
2643
          $dids = array_merge($dids, $new_dids);
2644
        }
2645

    
2646
        // Delete the display records if they are not still in use.
2647
        foreach (array_unique($dids) as $did) {
2648
          panels_delete_display($did);
2649
        }
2650

    
2651
        // Delete the {panelizer_entity} records.
2652
        db_delete('panelizer_entity')
2653
          ->condition('entity_type', $this->entity_type)
2654
          ->condition('revision_id', $revision_id)
2655
          ->condition('view_mode', $view_modes, 'IN')
2656
          ->condition('did', $dids, 'IN')
2657
          ->execute();
2658

    
2659
        // Reset the entity's cache. If the EntityCache module is enabled, this
2660
        // also resets its permanent cache.
2661
        entity_get_controller($this->entity_type)->resetCache(array($entity_id));
2662
      }
2663
    }
2664
  }
2665

    
2666
  /**
2667
   * Determine if a bundle is panelized.
2668
   */
2669
  public function is_panelized($bundle) {
2670
    if (strpos($bundle, '.') === FALSE) {
2671
      $has_bundle = !empty($this->plugin['bundles'][$bundle]);
2672
      $bundle_enabled = !empty($this->plugin['bundles'][$bundle]['status']);
2673
      return $has_bundle && $bundle_enabled;
2674
    }
2675
    else {
2676
      list($bundle, $view_mode) = explode('.', $bundle);
2677
      $has_bundle = !empty($this->plugin['bundles'][$bundle]);
2678
      $bundle_enabled = !empty($this->plugin['bundles'][$bundle]['status']);
2679
      $view_mode_enabled = !empty($this->plugin['bundles'][$bundle]['view modes'][$view_mode]['status']);
2680
      return $has_bundle && $bundle_enabled && $view_mode_enabled;
2681
    }
2682
  }
2683

    
2684
  /**
2685
   * Determine if a bundle has a default display.
2686
   *
2687
   * @param $bundle
2688
   *   A $bundle.$view_mode combo string. If no view mode is specified
2689
   *   then the 'page_manager' view mode will be assumed.
2690
   */
2691
  public function has_default_panel($bundle) {
2692
    if (strpos($bundle, '.') === FALSE) {
2693
      $bundle .= '.page_manager';
2694
    }
2695
    list($bundle, $view_mode) = explode('.', $bundle);
2696

    
2697
    // Is this display panelized?
2698
    $is_panelized = $this->is_panelized($bundle);
2699

    
2700
    // Load the default setting name.
2701
    $default = $this->get_default_display_name($bundle, $view_mode);
2702

    
2703
    // Verify the display exists.
2704
    $display_exists = $this->default_display_exists($default);
2705

    
2706
    return $is_panelized && !empty($default) && $display_exists;
2707
  }
2708

    
2709
  /**
2710
   * Determine if a bundle is allowed choices.
2711
   */
2712
  public function has_panel_choice($bundle) {
2713
    if (strpos($bundle, '.') === FALSE) {
2714
      $bundle .= '.page_manager';
2715
    }
2716
    list($bundle, $view_mode) = explode('.', $bundle);
2717

    
2718
    return $this->is_panelized($bundle) && !empty($this->plugin['bundles'][$bundle]['view modes'][$view_mode]['choice']);
2719
  }
2720

    
2721
  /**
2722
   * Get the default panels, keyed by names.
2723
   */
2724
  public function load_default_panelizer_objects($names) {
2725
    ctools_include('export');
2726
    $panelizers = ctools_export_load_object('panelizer_defaults', 'names', $names);
2727
    return $panelizers;
2728
  }
2729

    
2730
  /**
2731
   * Get the default panelizers for the given bundle.
2732
   */
2733
  public function get_default_panelizer_objects($bundle) {
2734
    if (strpos($bundle, '.') !== FALSE) {
2735
      list($bundle, $view_mode) = explode('.', $bundle);
2736
    }
2737
    $conditions = array(
2738
      'panelizer_type' => $this->entity_type,
2739
      'panelizer_key' => $bundle,
2740
    );
2741

    
2742
    // If the entity bundle is not panelized, nothing to do here.
2743
    if (!$this->is_panelized($bundle)) {
2744
      return array();
2745
    }
2746

    
2747
    if (!empty($view_mode)) {
2748
      // If this view mode is not panelized, nothing to do here.
2749
      if (!$this->is_panelized($bundle . '.' . $view_mode)) {
2750
        return array();
2751
      }
2752

    
2753
      $conditions['view_mode'] = $view_mode;
2754
    }
2755

    
2756
    ctools_include('export');
2757
    return ctools_export_load_object('panelizer_defaults', 'conditions', $conditions);
2758
  }
2759

    
2760
  /**
2761
   * Determine if the current user has access to the $panelizer.
2762
   */
2763
  public function access_default_panelizer_object($panelizer) {
2764
    // Automatically true for this, regardless of anything else.
2765
    if (user_access('administer panelizer')) {
2766
      return TRUE;
2767
    }
2768

    
2769
    ctools_include('context');
2770
    return user_access("administer panelizer $this->entity_type $panelizer->panelizer_key defaults") && ctools_access($panelizer->access, $this->get_contexts($panelizer));
2771
  }
2772

    
2773
  /**
2774
   * Implements a delegated hook_panelizer_defaults().
2775
   *
2776
   * This makes sure that all panelized entities configured to have a
2777
   * default actually have one.
2778
   */
2779
  public function hook_panelizer_defaults(&$panelizers) {
2780
    // For features integration, if they have modified a default and put
2781
    // it into the database, we do not want to show one as a default.
2782
    // Otherwise, features can't latch onto it.
2783
    $default_names = &drupal_static('panelizer_defaults_in_database', NULL);
2784
    if (!isset($default_names)) {
2785
      $default_names = drupal_map_assoc(db_query("SELECT name FROM {panelizer_defaults} WHERE name LIKE '%:default&'")->fetchCol());
2786
    }
2787

    
2788
    $entity_info = entity_get_info($this->entity_type);
2789

    
2790
    foreach ($this->plugin['bundles'] as $bundle => $info) {
2791
      // Don't bother if there are no
2792
      if (empty($info['status'])) {
2793
        continue;
2794
      }
2795

    
2796
      foreach ($this->plugin['view modes'] as $view_mode => $view_mode_info) {
2797
        if (!empty($info['view modes'][$view_mode]['status']) && !empty($info['view modes'][$view_mode]['default'])) {
2798
          $panelizer = $this->get_internal_default_panelizer($bundle, $view_mode);
2799
          if (empty($default_names[$panelizer->name]) && !isset($panelizers[$panelizer->name])) {
2800
            $panelizers[$panelizer->name] = $panelizer;
2801
          }
2802
        }
2803
      }
2804
    }
2805
  }
2806

    
2807
  /**
2808
   * An internal representation of a panelizer object, used to seed when
2809
   * we have none and want something to get started.
2810
   */
2811
  public function get_internal_default_panelizer($bundle, $view_mode) {
2812
    ctools_include('export');
2813
    $load_name = implode(':', array($this->entity_type, $bundle, 'default'));
2814
    $panelizer = ctools_export_crud_new('panelizer_defaults');
2815
    $panelizer->name = $load_name;
2816
    // Attach the view mode to the name, which is specially generated
2817
    // to ignore the specialty "page_manager" view mode.
2818
    if ($view_mode != 'page_manager') {
2819
      $panelizer->name .= ':' . $view_mode;
2820
    }
2821

    
2822
    $panelizer->panelizer_type = $this->entity_type;
2823
    $panelizer->panelizer_key = $bundle;
2824
    $panelizer->view_mode = $view_mode;
2825
    $panelizer->display = $this->get_default_display($bundle, $view_mode);
2826
    $panelizer->api_version = 1;
2827
    $panelizer->title = t('Default');
2828

    
2829
    return $panelizer;
2830
  }
2831

    
2832
  /**
2833
   * Load the named default display for the bundle.
2834
   */
2835
  public function get_default_panelizer_object($bundle, $name) {
2836
    if (strpos($bundle, '.') !== FALSE) {
2837
      list($bundle, $view_mode) = explode('.', $bundle);
2838
    }
2839
    else {
2840
      $view_mode = 'page_manager';
2841
    }
2842

    
2843
    // If the name is not in the format of entitytype:bundle:name which is
2844
    // the machine name used, split that out automatically.
2845
    if (strpos($name, ':') === FALSE) {
2846
      $name = implode(':', array($this->entity_type, $bundle, 'default'));
2847
      // This is the default view mode and older defaults won't have this,
2848
      // so we don't enforce it.
2849
      if ($view_mode != 'page_manager') {
2850
        $name .= ':' . $view_mode;
2851
      }
2852
    }
2853

    
2854
    ctools_include('export');
2855
    $panelizer = ctools_export_load_object('panelizer_defaults', 'names', array($name));
2856
    return reset($panelizer);
2857
  }
2858

    
2859
  /**
2860
   * Provide a default display for newly panelized entities.
2861
   *
2862
   * This should be implemented by the entity plugin.
2863
   */
2864
  function get_default_display($bundle, $view_mode) {
2865
    // This is a straight up empty display.
2866
    $display = panels_new_display();
2867
    $display->layout = 'flexible';
2868

    
2869
    $panes = array();
2870
    foreach (field_info_instances($this->entity_type, $bundle) as $field_name => $instance) {
2871
      $view_mode_settings = field_view_mode_settings($this->entity_type, $bundle);
2872
      $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default');
2873
      $field_display = $instance['display'][$actual_mode];
2874

    
2875
      $pane = panels_new_pane('entity_field', $this->entity_type . ':' . $field_name, TRUE);
2876
      $pane->configuration['formatter'] = $field_display['type'];
2877
      $pane->configuration['formatter_settings'] = $field_display['settings'];
2878
      $pane->configuration['label'] = $field_display['label'];
2879
      $pane->configuration['context'] = 'panelizer';
2880
      $panes[] = array(
2881
        '#pane' => $pane,
2882
        '#weight' => $field_display['weight'],
2883
      );
2884
    }
2885

    
2886
    // Use our #weights to sort these so they appear in whatever order the
2887
    // normal field configuration put them in.
2888
    uasort($panes, 'element_sort');
2889
    foreach ($panes as $pane) {
2890
      $display->add_pane($pane['#pane'], 'center');
2891
    }
2892

    
2893
    return $display;
2894
  }
2895

    
2896
  /**
2897
   * Get a panelizer object for the key.
2898
   *
2899
   * This must be implemented for each entity type.
2900
   */
2901
//  function get_panelizer_object($entity_id) {
2902
//  }
2903

    
2904
  /**
2905
   * Add entity specific form to the Panelizer settings form.
2906
   *
2907
   * This is primarily to allow bundle selection per entity type.
2908
   */
2909
  public function settings_form(&$form, &$form_state) {
2910
    // Add entity settings
2911
    // @todo change theme function name
2912
    $form['entities'][$this->entity_type] = array(
2913
      '#theme' => 'panelizer_settings_page_table',
2914
      '#header' => array(
2915
        array('data' => $this->entity_bundle_label(), 'style' => 'white-space:nowrap;'),
2916
        t('Panelize'),
2917
        t('Substitute view mode'),
2918
        t('Provide initial display'),
2919
        t('Allow panel choice'),
2920
        t('Default panel'),
2921
        t('Update existing entities to use this display'),
2922
        array('data' => t('Operations'), 'style' => 'white-space:nowrap;'),
2923
      ),
2924
      '#columns' => array(
2925
        'title',
2926
        'status',
2927
        'substitute',
2928
        'default',
2929
        'choice',
2930
        'selection',
2931
        'default revert',
2932
        'links',
2933
      ),
2934
    );
2935

    
2936
    $entity_info = entity_get_info($this->entity_type);
2937
    $bundles = $entity_info['bundles'];
2938

    
2939
    drupal_alter('panelizer_default_types', $bundles, $this->entity_type);
2940

    
2941
    foreach ($bundles as $bundle => $bundle_info) {
2942
      $view_mode_settings = array();
2943
      if (!empty($bundle)) {
2944
        $view_mode_settings = field_view_mode_settings($this->entity_type, $bundle);
2945
      }
2946
      $base_url = 'admin/structure/panelizer/' . $this->entity_type . '/' . $bundle;
2947
      $bundle_id = str_replace(array('][', '_', ' '), '-', '#edit-entities-' . $this->entity_type . '-' . $bundle . '-0');
2948

    
2949
      // Add the widgets that apply only to the bundle.
2950
      $form['entities'][$this->entity_type][$bundle][0]['title'] = array(
2951
        '#markup' => '<strong>' . $bundle_info['label'] . '</strong>',
2952
      );
2953

    
2954
      $form['entities'][$this->entity_type][$bundle][0]['status'] = array(
2955
        '#type' => 'checkbox',
2956
        '#title' => t('Panelize: @label', array('@label' => $bundle_info['label'])),
2957
        '#title_display' => 'invisible',
2958
        '#default_value' => !empty($this->plugin['bundles'][$bundle]['status']),
2959
      );
2960
      $form['entities'][$this->entity_type][$bundle][0]['help'] = array(
2961
        '#type' => 'hidden',
2962
        '#default_value' => !empty($this->plugin['bundles'][$bundle]['help']) ? $this->plugin['bundles'][$bundle]['help'] : '',
2963
      );
2964

    
2965
      // Set proper allowed content link for entire bundle based on status
2966
      if (!empty($this->plugin['bundles'][$bundle]['status'])) {
2967
        $links_array = array();
2968
        if (!empty($bundle_info['admin']['real path'])) {
2969
          $links_array['displays'] = array(
2970
            'title' => t('manage display'),
2971
            'href' => $bundle_info['admin']['real path'] . '/display',
2972
          );
2973
        }
2974
        $links_array['settings'] = array(
2975
          'title' => t('allowed content'),
2976
          'href' => $base_url . '/allowed',
2977
        );
2978
        $links = theme('links', array(
2979
          'links' => $links_array,
2980
          'attributes' => array('class' => array('links', 'inline')),
2981
        ));
2982
      }
2983
      else {
2984
        $links = t('Save to access allowed content');
2985
      }
2986

    
2987
      $form['entities'][$this->entity_type][$bundle][0]['links']['basic'] = array(
2988
        '#type' => 'item',
2989
        '#title' => $links,
2990
        '#states' => array(
2991
          'show' => array(
2992
            $bundle_id . '-status' => array('checked' => TRUE),
2993
          ),
2994
        ),
2995
      );
2996

    
2997
      $view_modes = $this->get_available_view_modes($bundle);
2998
      foreach ($view_modes as $view_mode => $view_mode_label) {
2999
        $view_mode_info = $this->plugin['view modes'][$view_mode];
3000

    
3001
        $base_id = str_replace(array('][', '_', ' '), '-', '#edit-entities-' . $this->entity_type . '-' . $bundle . '-' . $view_mode);
3002
        $base_url = 'admin/structure/panelizer/' . $this->entity_type . '/' . $bundle . '.' . $view_mode;
3003

    
3004
        if (!empty($this->plugin['bundles'][$bundle]['view modes'][$view_mode]) && is_array($this->plugin['bundles'][$bundle]['view modes'][$view_mode])) {
3005
          $settings = $this->plugin['bundles'][$bundle]['view modes'][$view_mode];
3006
        }
3007
        else {
3008
          $settings = array(
3009
            'status' => FALSE,
3010
            'default' => FALSE,
3011
            'choice' => FALSE
3012
          );
3013
        }
3014

    
3015
        if (empty($view_mode_info['panelizer special'])) {
3016
          $form['entities'][$this->entity_type][$bundle][$view_mode]['title'] = array(
3017
            '#markup' => '&nbsp;&nbsp;&nbsp;&nbsp;' . $view_mode_label,
3018
          );
3019
        }
3020
        else {
3021
          $form['entities'][$this->entity_type][$bundle][$view_mode]['title'] = array(
3022
            '#markup' => '<strong>' . $bundle_info['label'] . '</strong>',
3023
          );
3024
        }
3025

    
3026
        $form['entities'][$this->entity_type][$bundle][$view_mode]['status'] = array(
3027
          '#type' => 'checkbox',
3028
          '#default_value' => !empty($settings['status']),
3029
          '#title' => t(
3030
            'Panelize: @label, @bundle',
3031
            array(
3032
              '@label' => $bundle_info['label'],
3033
              '@bundle' => $view_mode_label
3034
            )
3035
          ),
3036
          '#title_display' => 'invisible',
3037
          '#states' => array(
3038
            'show' => array(
3039
              $bundle_id . '-status' => array('checked' => TRUE),
3040
            ),
3041
          ),
3042
        );
3043

    
3044
        $options = array('' => t('- Ignore this option -')) + $view_modes;
3045
        unset($options[$view_mode]);
3046
        $form['entities'][$this->entity_type][$bundle][$view_mode]['substitute'] = array(
3047
          '#type' => 'select',
3048
          '#options' => $options,
3049
          '#default_value' => $this->get_substitute($view_mode, $bundle),
3050
          '#title' => t(
3051
            'Substitute view mode: @label, @bundle',
3052
            array(
3053
              '@label' => $bundle_info['label'],
3054
              '@bundle' => $view_mode_label
3055
            )
3056
          ),
3057
          '#title_display' => 'invisible',
3058
          '#states' => array(
3059
            'show' => array(
3060
              $bundle_id . '-status' => array('checked' => TRUE),
3061
              $base_id . '-status' => array('checked' => TRUE),
3062
            ),
3063
          ),
3064
        );
3065

    
3066
        $form['entities'][$this->entity_type][$bundle][$view_mode]['default'] = array(
3067
          '#type' => 'checkbox',
3068
          '#default_value' => !empty($settings['default']),
3069
          '#title' => t(
3070
            'Provide initial display: @label, @bundle',
3071
            array(
3072
              '@label' => $bundle_info['label'],
3073
              '@bundle' => $view_mode_label
3074
            )
3075
          ),
3076
          '#title_display' => 'invisible',
3077
          '#states' => array(
3078
            'show' => array(
3079
              $bundle_id . '-status' => array('checked' => TRUE),
3080
              $base_id . '-status' => array('checked' => TRUE),
3081
              $base_id . '-substitute' => array('value' => ''),
3082
            ),
3083
          ),
3084
        );
3085

    
3086
        $form['entities'][$this->entity_type][$bundle][$view_mode]['choice'] = array(
3087
          '#type' => 'checkbox',
3088
          '#default_value' => !empty($settings['choice']),
3089
          '#title' => t(
3090
            'Allow panel choice: @label, @bundle',
3091
            array(
3092
              '@label' => $bundle_info['label'],
3093
              '@bundle' => $view_mode_label
3094
            )
3095
          ),
3096
          '#title_display' => 'invisible',
3097
          '#states' => array(
3098
            'show' => array(
3099
              $bundle_id . '-status' => array('checked' => TRUE),
3100
              $base_id . '-status' => array('checked' => TRUE),
3101
              $base_id . '-substitute' => array('value' => ''),
3102
            ),
3103
          ),
3104
        );
3105

    
3106
        // Obtain a list of all available panels for this view mode / bundle.
3107
        $panelizers = $this->get_default_panelizer_objects($bundle . '.' . $view_mode);
3108
        $options = array();
3109
        if (!empty($panelizers)) {
3110
          foreach ($panelizers as $name => $panelizer) {
3111
            // Don't show disabled displays.
3112
            if (empty($panelizer->disabled)) {
3113
              $options[$name] = $panelizer->title;
3114
            }
3115
          }
3116
        }
3117
        if (!empty($options)) {
3118
          ksort($options);
3119
        }
3120

    
3121
        // The default display to be used if nothing found.
3122
        $default_name = implode(':', array($this->entity_type, $bundle, 'default'));
3123
        $variable_name = 'panelizer_' . $this->entity_type . ':' . $bundle . ':' . $view_mode . '_selection';
3124
        if ($view_mode != 'page_manager') {
3125
          $default_name .= ':' . $view_mode;
3126
        }
3127
        // If this has not been set previously, use the 'default' as the default
3128
        // selection.
3129
        $default_value = variable_get($variable_name, FALSE);
3130
        if (empty($default_value)) {
3131
          $default_value = $default_name;
3132
        }
3133

    
3134
        // First time this is displayed there won't be any defaults assigned, so
3135
        // show a placeholder indicating the page needs to be saved before they
3136
        // will show.
3137
        if (count($options) == 0) {
3138
          if ($default_value == $default_name) {
3139
            $options = array('' => t('Save to access selector'));
3140
          }
3141
          else {
3142
            $options = array('' => t('No displays created yet'));
3143
          }
3144
        }
3145
        // Indicate which item is actually the default.
3146
        if (count($options) > 1 && isset($options[$default_value])) {
3147
          $options[$default_value] .= ' (' . t('default') . ')';
3148
        }
3149
        $form['entities'][$this->entity_type][$bundle][$view_mode]['selection'] = array(
3150
          '#type' => 'select',
3151
          '#options' => $options,
3152
          '#default_value' => $default_value,
3153
          '#title' => t(
3154
            'Default panel: @label, @bundle',
3155
            array(
3156
              '@label' => $bundle_info['label'],
3157
              '@bundle' => $view_mode_label
3158
            )
3159
          ),
3160
          '#title_display' => 'invisible',
3161
          '#states' => array(
3162
            'show' => array(
3163
              $bundle_id . '-status' => array('checked' => TRUE),
3164
              $base_id . '-status' => array('checked' => TRUE),
3165
              $base_id . '-substitute' => array('value' => ''),
3166
            ),
3167
          ),
3168
          '#disabled' => count($options) == 1,
3169
        );
3170
        $form['entities'][$this->entity_type][$bundle][$view_mode]['default revert'] = array(
3171
          '#type' => 'checkbox',
3172
          '#default_value' => FALSE,
3173
          '#title' => t(
3174
            'Update existing entities to use this display: @label, @bundle',
3175
            array(
3176
              '@label' => $bundle_info['label'],
3177
              '@bundle' => $view_mode_label
3178
            )
3179
          ),
3180
          '#title_display' => 'invisible',
3181
          '#states' => array(
3182
            'show' => array(
3183
              $bundle_id . '-status' => array('checked' => TRUE),
3184
              $base_id . '-status' => array('checked' => TRUE),
3185
              $base_id . '-substitute' => array('value' => ''),
3186
            ),
3187
          ),
3188
          '#disabled' => count($options) == 1,
3189
        );
3190

    
3191
        $form['entities'][$this->entity_type][$bundle][$view_mode]['links'] = array(
3192
          '#prefix' => '<div class="container-inline">',
3193
          '#suffix' => '</div>',
3194
        );
3195

    
3196
        // Panelize is enabled and a default display will be provided.
3197
        if (!empty($settings['status']) && !empty($settings['default']) && empty($settings['choice'])) {
3198
          $links_array = array();
3199
          foreach (panelizer_operations() as $path => $operation) {
3200
            $links_array[$path] = array(
3201
              'title' => $operation['link title'],
3202
              'href' => $base_url . '/' . $path,
3203
            );
3204
          }
3205

    
3206
          $links = theme('links', array(
3207
            'links' => $links_array,
3208
            'attributes' => array('class' => array('links', 'inline')),
3209
          ));
3210
        }
3211
        else {
3212
          $links = t('Save to access default panel');
3213
        }
3214

    
3215
        $form['entities'][$this->entity_type][$bundle][$view_mode]['links']['default'] = array(
3216
          '#type' => 'item',
3217
          '#title' => $links,
3218
          '#states' => array(
3219
            'show' => array(
3220
              $bundle_id . '-status' => array('checked' => TRUE),
3221
              $base_id . '-status' => array('checked' => TRUE),
3222
              $base_id . '-default' => array('checked' => TRUE),
3223
              $base_id . '-choice' => array('checked' => FALSE),
3224
              $base_id . '-substitute' => array('value' => ''),
3225
            ),
3226
          ),
3227
        );
3228

    
3229
        if (!empty($settings['status']) && !empty($settings['choice'])) {
3230
          $links_array = array(
3231
            'list' => array(
3232
              'title' => t('list'),
3233
              'href' => $base_url . '/list',
3234
            ),
3235
          );
3236

    
3237
          $links = theme('links', array(
3238
            'links' => $links_array,
3239
            'attributes' => array('class' => array('links', 'inline')),
3240
          ));
3241
        }
3242
        else {
3243
          $links = t('Save to access display list');
3244
        }
3245

    
3246
        $form['entities'][$this->entity_type][$bundle][$view_mode]['links']['default2'] = array(
3247
          '#type' => 'item',
3248
          '#title' => $links,
3249
          '#states' => array(
3250
            'show' => array(
3251
              $bundle_id . '-status' => array('checked' => TRUE),
3252
              $base_id . '-status' => array('checked' => TRUE),
3253
              $base_id . '-choice' => array('checked' => TRUE),
3254
              $base_id . '-substitute' => array('value' => ''),
3255
            ),
3256
          ),
3257
        );
3258

    
3259
        // Additional messages if this display is enabled.
3260
        if (empty($form_state['input']) && $view_mode == 'page_manager' && !empty($settings['status'])) {
3261
          $this->check_page_manager_status();
3262
        }
3263
      }
3264
    }
3265
    $form['#attached'] = array(
3266
      'js' => array(ctools_attach_js('states-show')),
3267
    );
3268
  }
3269

    
3270
  /**
3271
   * Validate entity specific settings on the Panelizer settings form.
3272
   */
3273
  public function settings_form_validate(&$form, &$form_state) {
3274

    
3275
  }
3276

    
3277
  /**
3278
   * Submit entity specific settings on the Panelizer settings form.
3279
   */
3280
  public function settings_form_submit(&$form, &$form_state) {
3281
    if (empty($form_state['values']['entities'][$this->entity_type])) {
3282
      return;
3283
    }
3284

    
3285
    foreach ($form_state['values']['entities'][$this->entity_type] as $bundle => $values) {
3286
      // Rewrite our settings because they're not quite in the right format in
3287
      // the form.
3288
      $settings = array(
3289
        'status' => $values[0]['status'],
3290
        'view modes' => array(),
3291
      );
3292
      if (!empty($values[0]['status'])) {
3293
        $settings['help'] = $values[0]['help'];
3294

    
3295
        foreach ($values as $view_mode => $config) {
3296
          if (!empty($view_mode) && !empty($config)) {
3297
            // Fix the configuration.
3298
            // Make sure each setting is disabled if the view mode is
3299
            // disabled.
3300
            if (empty($config['status'])) {
3301
              foreach ($config as $key => $val) {
3302
                $config[$key] = 0;
3303
              }
3304
            }
3305

    
3306
            // Save the default display for this bundle to a variable so that it
3307
            // may be controlled separately.
3308
            if (!empty($config['selection'])) {
3309
              $variable_name = 'panelizer_' . $this->entity_type . ':' . $bundle . ':' . $view_mode . '_selection';
3310
              $old_value = variable_get($variable_name, NULL);
3311
              $new_value = $config['selection'];
3312
              variable_set($variable_name, $config['selection']);
3313

    
3314
              // Cleanup.
3315

    
3316
              // Additional cleanup if the default display was changed.
3317
              if (!is_null($old_value) && $old_value != $new_value) {
3318
                // The user specifically requested that existing entities are
3319
                // to be updated to the new display.
3320
                if (!empty($config['default revert'])) {
3321
                  $updated_count = db_update('panelizer_entity')
3322
                    ->fields(array('name' => $new_value))
3323
                    ->condition('name', $old_value)
3324
                    ->execute();
3325
                  drupal_set_message(t('@count @entity records were updated to the new Panelizer display for the @mode view mode.', array('@count' => $updated_count, '@entity' => $this->entity_type, '@mode' => $view_mode)));
3326

    
3327
                  // If EntityCache is enabled, clear all records of this type.
3328
                  // This is a little heavy-handed, but I don't believe there's
3329
                  // an easy way to clear only entities of certain types
3330
                  // without querying for them first, which could trigger an
3331
                  // execution timeout.
3332
                  if (module_exists('entitycache')) {
3333
                    cache_clear_all('*', 'cache_entity_' . $this->entity_type, TRUE);
3334
                  }
3335
                }
3336
              }
3337
            }
3338

    
3339
            // Don't save some settings with the rest of the settings bundle.
3340
            unset($config['selection']);
3341
            unset($config['default revert']);
3342

    
3343
            $settings['view modes'][$view_mode] = $config;
3344
          }
3345
        }
3346
      }
3347
      variable_set('panelizer_defaults_' . $this->entity_type . '_' . $bundle, $settings);
3348
    }
3349

    
3350
    // @todo if we enable caching of the plugins, which we should, this
3351
    // needs to clear that cache so they get reloaded.
3352
  }
3353

    
3354
  /**
3355
   * Render the panels display for a given panelizer entity.
3356
   *
3357
   * @param stdClass $entity
3358
   *   A fully-loaded entity object controlled by panelizer.
3359
   * @param array $args
3360
   *   Optional array of arguments to pass to the panels display.
3361
   * @param string $address
3362
   *   An optional address to send to the renderer to use for addressable
3363
   *   content.
3364
   * @param array $extra_contexts
3365
   *   An optional array of extra context objects that will be added to the
3366
   *   display.
3367
   *
3368
   * @return array
3369
   *   If the entity isn't panelized, this returns NULL. Otherwise, it returns an
3370
   *   associative array as meant for use with CTools with the following keys:
3371
   *   - 'content': String containing the rendered panels display output.
3372
   *   - 'no_blocks': Boolean defining if the panels display wants to hide core
3373
   *      blocks or not when being rendered.
3374
   */
3375
  function render_entity($entity, $view_mode, $langcode = NULL, $args = array(), $address = NULL, $extra_contexts = array()) {
3376
    list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
3377

    
3378
    // Optionally substitute the view mode with another one.
3379
    $substitute = $this->get_substitute($view_mode, $bundle);
3380
    if (!empty($substitute)) {
3381
      $view_mode = $substitute;
3382
    }
3383

    
3384
    // Nothing configured for this view mode.
3385
    if (empty($entity->panelizer[$view_mode]) || empty($entity->panelizer[$view_mode]->display)) {
3386
      return FALSE;
3387
    }
3388

    
3389
    $panelizer = $entity->panelizer[$view_mode];
3390
    $display = $panelizer->display;
3391

    
3392
    $display->context = $this->get_contexts($panelizer, $entity) + $extra_contexts;
3393
    $display->args = $args;
3394
    $display->css_id = $panelizer->css_id;
3395

    
3396
    // This means the IPE will use our cache which means it will get appropriate
3397
    // allowed content should it be selected.
3398
    $display->cache_key = implode(':', array_filter(array('panelizer', $this->entity_type, $entity_id, $view_mode, $revision_id)));
3399

    
3400
    // Check to see if there is any CSS.
3401
    if (!empty($panelizer->css)) {
3402
      ctools_include('css');
3403
      $filename = ctools_css_retrieve($display->cache_key);
3404
      if (!$filename) {
3405
        $filename = ctools_css_store($display->cache_key, $panelizer->css);
3406
      }
3407
      drupal_add_css($filename, array('group' => CSS_THEME));
3408
    }
3409

    
3410
    if ($view_mode == 'page_manager') {
3411
      // We think this is handled as a page, so set the current page display.
3412
      panels_get_current_page_display($display);
3413
    }
3414

    
3415
    // Allow applications to alter the panelizer and the display before
3416
    // rendering them.
3417
    drupal_alter('panelizer_pre_render', $panelizer, $display, $entity);
3418

    
3419
    ctools_include('plugins', 'panels');
3420
    $renderer = panels_get_renderer($panelizer->pipeline, $display);
3421

    
3422
    // If the IPE is enabled, but the user does not have access to edit
3423
    // the entity, load the standard renderer instead.
3424

    
3425
    // Use class_parents so we don't try to autoload the class we are testing.
3426
    $parents = class_parents($renderer);
3427
    if (!empty($parents['panels_renderer_editor']) && (!$this->panelizer_access('content', $entity, $view_mode) && !$this->entity_access('update', $entity))) {
3428
      $renderer = panels_get_renderer_handler('standard', $display);
3429
    }
3430

    
3431
    $renderer->address = $address;
3432

    
3433
    $info = array(
3434
      'title' => $panelizer->display->get_title(),
3435
      'content' => panels_render_display($display, $renderer),
3436
      'no_blocks' => !empty($panelizer->no_blocks),
3437
    );
3438

    
3439
    $info['classes_array'] = array();
3440

    
3441
    if (!empty($panelizer->css_class)) {
3442
      foreach (explode(' ', $panelizer->css_class) as $class) {
3443
        $class = ctools_context_keyword_substitute($class, array(), $display->context);
3444
        if ($class) {
3445
          $info['classes_array'][] = drupal_html_class($class);
3446
        }
3447
      }
3448
    }
3449

    
3450
    if (!empty($parents['panels_renderer_editor'])) {
3451
      $path = drupal_get_path('module', 'panelizer');
3452
      ctools_add_js('panelizer-ipe', 'panelizer');
3453
      drupal_add_js($path . "/js/panelizer-ipe.js", array('group' => JS_LIBRARY));
3454
      drupal_add_css($path . "/css/panelizer-ipe.css");
3455
    }
3456

    
3457
    return $info;
3458
  }
3459

    
3460
  /**
3461
   * Fetch an object array of CTools contexts from panelizer information.
3462
   */
3463
  public function get_contexts($panelizer, $entity = NULL) {
3464
    ctools_include('context');
3465
    if (empty($panelizer->base_contexts)) {
3466
      $panelizer->base_contexts = $this->get_base_contexts($entity);
3467
    }
3468

    
3469
    $contexts = ctools_context_load_contexts($panelizer);
3470
    return $contexts;
3471
  }
3472

    
3473
  /**
3474
   * Callback to get the base context for a panelized entity
3475
   */
3476
  public function get_base_contexts($entity = NULL) {
3477
    ctools_include('context');
3478
    if ($entity) {
3479
      $context = ctools_context_create('entity:' . $this->entity_type, $entity);
3480
    }
3481
    else {
3482
      $context = ctools_context_create_empty('entity:' . $this->entity_type);
3483
      // The placeholder is needed to create the form used for the live
3484
      // preview.
3485
      $context->placeholder = array(
3486
        'type' => 'context',
3487
        'conf' => array(
3488
          'name' => $this->entity_type,
3489
          'identifier' => $this->entity_identifier($entity),
3490
          'keyword' => $this->entity_type,
3491
          'context_settings' => array(),
3492
        ),
3493
      );
3494
    }
3495

    
3496
    $context->identifier = $this->entity_identifier($entity);
3497
    $context->keyword = $this->entity_type;
3498
    return array('panelizer' => $context);
3499
  }
3500

    
3501
  /**
3502
   * Get the visible identifier if the identity.
3503
   *
3504
   * This is overridable because it can be a bit awkward using the
3505
   * default label.
3506
   */
3507
  public function entity_identifier($entity) {
3508
    $entity_info = entity_get_info($this->entity_type);
3509
    return t('This @entity', array('@entity' => $entity_info['label']));
3510
  }
3511

    
3512
  // Admin screens use a title callback for admin pages. This is used
3513
  // to fill in that title.
3514
  public function get_bundle_title($bundle) {
3515
    $entity_info = entity_get_info($this->entity_type);
3516

    
3517
    return isset($entity_info['bundles'][$bundle]['label']) ? $entity_info['bundles'][$bundle]['label'] : '';
3518
  }
3519

    
3520
  /**
3521
   * Get the name of bundles on the entity.
3522
   *
3523
   * Entity API doesn't give us a way to determine this, so the class must
3524
   * do this.
3525
   *
3526
   * @return
3527
   *   A translated, safe string.
3528
   */
3529
  public function entity_bundle_label() {
3530
    $entity_info = entity_get_info($this->entity_type);
3531
    return t('@entity bundle', array('@entity' => $entity_info['label']));
3532
  }
3533

    
3534
  /**
3535
   * Fetch the entity out of a build for hook_entity_view.
3536
   *
3537
   * @param $build
3538
   *   The render array that contains the entity.
3539
   */
3540
  public function get_entity_view_entity($build) {
3541
    $element = '#' . $this->entity_type;
3542
    if (isset($build[$element])) {
3543
      return $build[$element];
3544
    }
3545
    else if (isset($build['#entity'])) {
3546
      return $build['#entity'];
3547
    }
3548
  }
3549

    
3550
  /**
3551
   * Implement views support for panelizer entity types.
3552
   */
3553
  public function hook_views_data_alter(&$items) {
3554
    $entity_info = entity_get_info($this->entity_type);
3555
    if (!empty($entity_info['base table'])) {
3556
      $table = $entity_info['base table'];
3557
      $items[$table]['panelizer_link'] = array(
3558
        'field' => array(
3559
          'title' => t('Panelizer link'),
3560
          'help' => t('Provide a link to panelizer-related operations on the content.'),
3561
          'handler' => 'panelizer_handler_field_link',
3562
          'entity_type' => $this->entity_type,
3563
        ),
3564
      );
3565
      $items[$table]['panelizer_status'] = array(
3566
        'field' => array(
3567
          'title' => t('Panelizer status'),
3568
          'help' => t('Display whether an entity is panelized and which panelizer option it is using.'),
3569
          'handler' => 'panelizer_handler_panelizer_status',
3570
          'entity_type' => $this->entity_type,
3571
        ),
3572
      );
3573

    
3574
      // Join on revision id if possible or entity id if not.
3575
      if (!empty($entity_info['entity keys']['revision'])) {
3576
        $id_field = $entity_info['entity keys']['revision'];
3577
        $field = 'revision_id';
3578
      }
3579
      else {
3580
        $id_field = $entity_info['entity keys']['id'];
3581
        $field = 'entity_id';
3582
      }
3583

    
3584
      $items['panelizer_entity_' . $table]['table']['join'] = array(
3585
        $table => array(
3586
          'handler' => 'views_join',
3587
          'table' => 'panelizer_entity',
3588
          'left_table' => $table,
3589
          'left_field' => $id_field,
3590
          'field' => $field,
3591
          'extra' => array(array(
3592
            'field' => 'entity_type',
3593
            'value' => $this->entity_type,
3594
            'operator' => '=',
3595
          )),
3596
        ),
3597
      );
3598

    
3599
      $items['panelizer_entity_' . $table]['table']['group'] = $items[$table]['table']['group'];
3600

    
3601
      $items['panelizer_entity_' . $table]['name'] = array(
3602
        'filter' => array(
3603
          'title' => t('Panelizer status'),
3604
          'help' => t('Filter based upon panelizer status.'),
3605
          'handler' => 'panelizer_handler_filter_panelizer_status',
3606
          'entity_type' => $this->entity_type,
3607
        ),
3608
      );
3609
    }
3610
  }
3611

    
3612
  /**
3613
   * Preprocess the entity view mode template.
3614
   */
3615
  public function preprocess_panelizer_view_mode(&$vars, $entity, $element, $panelizer, $info) {
3616
    $vars['classes_array'][] = drupal_html_class($this->entity_type);
3617
    $vars['classes_array'][] = drupal_html_class($this->entity_type . '-' . $element['#view_mode']);
3618
    $vars['classes_array'][] = drupal_html_class($this->entity_type . '-' . $element['#panelizer_bundle']);
3619
    $vars['classes_array'][] = drupal_html_class($this->entity_type . '-' . $element['#panelizer_entity_id']);
3620
    if (!empty($entity->preview)) {
3621
      $vars['classes_array'][] = drupal_html_class($this->entity_type . '-preview');
3622
    }
3623

    
3624
    if (!empty($panelizer->title_element)) {
3625
      $vars['title_element'] = $panelizer->title_element;
3626
    }
3627
    else {
3628
      $vars['title_element'] = 'h2';
3629
    }
3630

    
3631
    $vars['content'] = $info['content'];
3632
    if (!empty($info['title'])) {
3633
      $vars['title'] = $info['title'];
3634
    }
3635

    
3636
    if (!empty($info['classes_array'])) {
3637
      $vars['classes_array'] = array_merge($vars['classes_array'], $info['classes_array']);
3638
    }
3639

    
3640
    if (!empty($panelizer->link_to_entity)) {
3641
      list($entity_id, $revision_id, $bundle) = entity_extract_ids($this->entity_type, $entity);
3642

    
3643
      $bits = explode('/', $this->plugin['entity path']);
3644
      foreach ($bits as $count => $bit) {
3645
        if (strpos($bit, '%') === 0) {
3646
          $bits[$count] = $entity_id;
3647
        }
3648
      }
3649
      $vars['entity_url'] = url(implode('/', $bits));
3650
    }
3651
  }
3652

    
3653
  /**
3654
   * Identify whether page manager is enabled for this entity type.
3655
   */
3656
  public function is_page_manager_enabled() {
3657
    return variable_get('page_manager_' . $this->entity_type . '_view_disabled', TRUE);
3658
  }
3659
}
3660

    
3661
function panelizer_entity_default_bundle_form_submit($form, &$form_state) {
3662
  $bundle = $form['panelizer']['#bundle'];
3663
  $type_location = $form['panelizer']['#location'];
3664
  $form_state['panelizer_entity_handler']->add_bundle_setting_form_submit($form, $form_state, $bundle, $type_location);
3665
}