Projet

Général

Profil

Paste
Télécharger (38,8 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / file_entity / file_entity.admin.inc @ 87dbc3bf

1
<?php
2
/**
3
 * @file
4
 * File administration and module settings UI.
5
 */
6

    
7
require_once dirname(__FILE__) . '/file_entity.pages.inc';
8

    
9
/**
10
 * List file administration filters that can be applied.
11
 */
12
function file_filters() {
13
  $visible_steam_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_VISIBLE);
14
  $options = array();
15
  foreach ($visible_steam_wrappers as $scheme => $information) {
16
    $options[$scheme] = check_plain($information['name']);
17
  }
18
  $filters['uri'] = array(
19
    'title' => t('scheme'),
20
    'options' => array(
21
      '[any]' => t('any'),
22
    ) + $options,
23
  );
24
  $filters['type'] = array(
25
    'title' => t('type'),
26
    'options' => array(
27
      '[any]' => t('any'),
28
    ) + file_entity_type_get_names(),
29
  );
30
  return $filters;
31
}
32

    
33
/**
34
 * Apply filters for file administration filters based on session.
35
 *
36
 * @param object $query
37
 *   A SelectQuery to which the filters should be applied.
38
 */
39
function file_entity_build_filter_query(SelectQueryInterface $query) {
40
  // Build query.
41
  $filter_data = isset($_SESSION['file_entity_overview_filter']) ? $_SESSION['file_entity_overview_filter'] : array();
42
  foreach ($filter_data as $index => $filter) {
43
    list($key, $value) = $filter;
44
    switch ($key) {
45
      case 'uri':
46
        $query->condition('fm.' . $key, $value . '%', 'LIKE');
47
        break;
48

    
49
      case 'type':
50
        $query->condition('fm.' . $key, $value);
51
        break;
52

    
53
    }
54
  }
55
}
56

    
57
/**
58
 * Return form for file administration filters.
59
 */
60
function file_entity_filter_form() {
61
  $session = isset($_SESSION['file_entity_overview_filter']) ? $_SESSION['file_entity_overview_filter'] : array();
62
  $filters = file_filters();
63

    
64
  $i = 0;
65
  $form['filters'] = array(
66
    '#type' => 'fieldset',
67
    '#title' => t('Show only items where'),
68
    '#theme' => 'exposed_filters__file_entity',
69
  );
70
  foreach ($session as $filter) {
71
    list($type, $value) = $filter;
72
    if ($type == 'term') {
73
      // Load term name from DB rather than search and parse options array.
74
      $value = module_invoke('taxonomy', 'term_load', $value);
75
      $value = $value->name;
76
    }
77
    else {
78
      $value = $filters[$type]['options'][$value];
79
    }
80
    $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
81
    if ($i++) {
82
      $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
83
    }
84
    else {
85
      $form['filters']['current'][] = array('#markup' => t('where %property is %value', $t_args));
86
    }
87
    if (in_array($type, array('type', 'uri'))) {
88
      // Remove the option if it is already being filtered on.
89
      unset($filters[$type]);
90
    }
91
  }
92

    
93
  $form['filters']['status'] = array(
94
    '#type' => 'container',
95
    '#attributes' => array('class' => array('clearfix')),
96
    '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
97
  );
98
  $form['filters']['status']['filters'] = array(
99
    '#type' => 'container',
100
    '#attributes' => array('class' => array('filters')),
101
  );
102
  foreach ($filters as $key => $filter) {
103
    $form['filters']['status']['filters'][$key] = array(
104
      '#type' => 'select',
105
      '#options' => $filter['options'],
106
      '#title' => $filter['title'],
107
      '#default_value' => '[any]',
108
    );
109
  }
110

    
111
  $form['filters']['status']['actions'] = array(
112
    '#type' => 'actions',
113
    '#attributes' => array('class' => array('container-inline')),
114
  );
115
  if (count($filters)) {
116
    $form['filters']['status']['actions']['submit'] = array(
117
      '#type' => 'submit',
118
      '#value' => count($session) ? t('Refine') : t('Filter'),
119
    );
120
  }
121
  if (count($session)) {
122
    $form['filters']['status']['actions']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
123
    $form['filters']['status']['actions']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
124
  }
125

    
126
  drupal_add_js('misc/form.js');
127

    
128
  return $form;
129
}
130

    
131
/**
132
 * Process result from file administration filter form.
133
 */
134
function file_entity_filter_form_submit($form, &$form_state) {
135
  $filters = file_filters();
136
  switch ($form_state['values']['op']) {
137
    case t('Filter'):
138
    case t('Refine'):
139
      // Apply every filter that has a choice selected other than 'any'.
140
      foreach ($filters as $filter => $options) {
141
        if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
142
          // Flatten the options array to accommodate hierarchical/nested
143
          // options.
144
          $flat_options = form_options_flatten($filters[$filter]['options']);
145
          // Only accept valid selections offered on the dropdown, block bad
146
          // input.
147
          if (isset($flat_options[$form_state['values'][$filter]])) {
148
            $_SESSION['file_entity_overview_filter'][] = array($filter, $form_state['values'][$filter]);
149
          }
150
        }
151
      }
152
      break;
153

    
154
    case t('Undo'):
155
      array_pop($_SESSION['file_entity_overview_filter']);
156
      break;
157

    
158
    case t('Reset'):
159
      $_SESSION['file_entity_overview_filter'] = array();
160
      break;
161

    
162
  }
163
}
164

    
165
/**
166
 * Make mass update of files.
167
 *
168
 * Change all files in the $files array to update them with the field values in
169
 * $updates.
170
 *
171
 * IMPORTANT NOTE: This function is intended to work when called
172
 * from a form submit handler. Calling it outside of the form submission
173
 * process may not work correctly.
174
 *
175
 * @param array $files
176
 *   Array of file fids to update.
177
 * @param array $updates
178
 *   Array of key/value pairs with file field names and the
179
 *   value to update that field to.
180
 */
181
function file_entity_mass_update($files, $updates) {
182
  // We use batch processing to prevent timeout when updating a large number
183
  // of files.
184
  if (count($files) > 10) {
185
    $batch = array(
186
      'operations' => array(
187
        array(
188
          '_file_entity_mass_update_batch_process',
189
          array($files, $updates),
190
        ),
191
      ),
192
      'finished' => '_file_entity_mass_update_batch_finished',
193
      'title' => t('Processing'),
194
      // We use a single multi-pass operation, so the default
195
      // 'Remaining x of y operations' message will be confusing here.
196
      'progress_message' => '',
197
      'error_message' => t('The update has encountered an error.'),
198
      // The operations do not live in the .module file, so we need to
199
      // tell the batch engine which file to load before calling them.
200
      'file' => drupal_get_path('module', 'file_entity') . '/file_entity.admin.inc',
201
    );
202
    batch_set($batch);
203
  }
204
  else {
205
    foreach ($files as $fid) {
206
      _file_entity_mass_update_helper($fid, $updates);
207
    }
208
    drupal_set_message(t('The update has been performed.'));
209
  }
210
}
211

    
212
/**
213
 * File Mass Update - helper function.
214
 */
215
function _file_entity_mass_update_helper($fid, $updates) {
216
  $file = file_load($fid);
217
  // For efficiency manually save the original file before applying any changes.
218
  $file->original = clone $file;
219
  foreach ($updates as $name => $value) {
220
    $file->$name = $value;
221
  }
222
  file_save($file);
223
  return $file;
224
}
225

    
226
/**
227
 * File Mass Update Batch operation.
228
 */
229
function _file_entity_mass_update_batch_process($files, $updates, &$context) {
230
  if (!isset($context['sandbox']['progress'])) {
231
    $context['sandbox']['progress'] = 0;
232
    $context['sandbox']['max'] = count($files);
233
    $context['sandbox']['files'] = $files;
234
  }
235

    
236
  // Process files by groups of 5.
237
  $count = min(5, count($context['sandbox']['files']));
238
  for ($i = 1; $i <= $count; $i++) {
239
    // For each fid, load the file, reset the values, and save it.
240
    $fid = array_shift($context['sandbox']['files']);
241
    $file = _file_entity_mass_update_helper($fid, $updates);
242

    
243
    // Store result for post-processing in the finished callback.
244
    $context['results'][] = l($file->filename, 'file/' . $file->fid);
245

    
246
    // Update our progress information.
247
    $context['sandbox']['progress']++;
248
  }
249

    
250
  // Inform the batch engine that we are not finished,
251
  // and provide an estimation of the completion level we reached.
252
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
253
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
254
  }
255
}
256

    
257
/**
258
 * File Mass Update Batch 'finished' callback.
259
 */
260
function _file_entity_mass_update_batch_finished($success, $results, $operations) {
261
  if ($success) {
262
    drupal_set_message(t('The update has been performed.'));
263
  }
264
  else {
265
    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
266
    $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
267
    $message .= theme('item_list', array('items' => $results));
268
    drupal_set_message($message);
269
  }
270
}
271

    
272
/**
273
 * Menu callback: file administration.
274
 */
275
function file_entity_admin_file($form, $form_state) {
276
  if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
277
    return file_entity_multiple_delete_confirm($form, $form_state, array_filter($form_state['values']['files']));
278
  }
279
  $form['filter'] = file_entity_filter_form();
280
  $form['#submit'][] = 'file_entity_filter_form_submit';
281
  $form['admin'] = file_entity_admin_files();
282

    
283
  return $form;
284
}
285

    
286
/**
287
 * Form builder: Builds the file administration overview.
288
 */
289
function file_entity_admin_files() {
290
  $admin_access = user_access('administer files');
291

    
292
  // Build the 'Update options' form.
293
  $form['options'] = array(
294
    '#type' => 'fieldset',
295
    '#title' => t('Update options'),
296
    '#attributes' => array('class' => array('container-inline')),
297
    '#access' => $admin_access,
298
  );
299
  $options = array();
300
  foreach (module_invoke_all('file_operations') as $operation => $array) {
301
    $options[$operation] = $array['label'];
302
  }
303
  $form['options']['operation'] = array(
304
    '#type' => 'select',
305
    '#title' => t('Operation'),
306
    '#title_display' => 'invisible',
307
    '#options' => $options,
308
    '#default_value' => 'approve',
309
  );
310
  $form['options']['submit'] = array(
311
    '#type' => 'submit',
312
    '#value' => t('Update'),
313
    '#validate' => array('file_entity_admin_files_validate'),
314
    '#submit' => array('file_entity_admin_files_submit'),
315
  );
316

    
317
  // Build the sortable table header.
318
  $header = array(
319
    'title' => array('data' => t('Title'), 'field' => 'fm.filename'),
320
    'type' => array('data' => t('Type'), 'field' => 'fm.type'),
321
    'size' => array('data' => t('Size'), 'field' => 'fm.filesize'),
322
    'author' => t('Author'),
323
    'timestamp' => array(
324
      'data' => t('Updated'),
325
      'field' => 'fm.timestamp',
326
      'sort' => 'desc'),
327
    'usage' => array('data' => t('Used in'), 'field' => 'total_count'),
328
    'operations' => array('data' => t('Operations')),
329
  );
330

    
331
  $query = db_select('file_managed', 'fm')->extend('PagerDefault')->extend('TableSort');
332
  $query->leftJoin('file_usage', 'fu', 'fm.fid = fu.fid');
333
  $query->groupBy('fm.fid');
334
  $query->addExpression('SUM(fu.count)', 'total_count');
335
  file_entity_build_filter_query($query);
336

    
337
  $result = $query
338
    ->fields('fm', array('fid', 'uid'))
339
    ->limit(50)
340
    ->orderByHeader($header)
341
    ->addTag('file_access')
342
    ->execute()
343
    ->fetchAllAssoc('fid');
344
  $files = file_load_multiple(array_keys($result));
345

    
346
  $uids = array();
347
  foreach ($files as $file) {
348
    $uids[] = $file->uid;
349
  }
350
  $accounts = !empty($uids) ? user_load_multiple(array_unique($uids)) : array();
351

    
352
  // Prepare the list of files.
353
  $destination = drupal_get_destination();
354
  $options = array();
355
  foreach ($files as $file) {
356
    $file_type = file_type_load($file->type);
357
    $options[$file->fid] = array(
358
      'title' => array(
359
        'data' => array(
360
          '#type' => 'link',
361
          '#title' => $file->filename,
362
          '#href' => 'file/' . $file->fid,
363
        ),
364
      ),
365
      'type' => $file_type ? check_plain($file_type->label) : FILE_TYPE_NONE,
366
      'size' => format_size($file->filesize),
367
      'author' => theme('username', array('account' => $accounts[$file->uid])),
368
      'timestamp' => format_date($file->timestamp, 'short'),
369
      'usage' => format_plural((int) $result[$file->fid]->total_count, '1 place', '@count places'),
370
    );
371

    
372
    // Show a warning for files that do not exist.
373
    if (@!is_file($file->uri)) {
374
      $options[$file->fid]['#attributes']['class'][] = 'error';
375
      if (!file_stream_wrapper_get_instance_by_uri($file->uri)) {
376
        $options[$file->fid]['#attributes']['title'] = t('The stream wrapper for @scheme files is missing.', array('@scheme' => file_uri_scheme($file->uri)));
377
      }
378
      else {
379
        $options[$file->fid]['#attributes']['title'] = t('The file does not exist.');
380
      }
381
    }
382

    
383
    // Build a list of all the accessible operations for the current file.
384
    $operations = array();
385
    if (file_entity_access('update', $file)) {
386
      // Convert the usage count to a link.
387
      $options[$file->fid]['usage'] = l($options[$file->fid]['usage'], 'file/' . $file->fid . '/usage');
388
      $operations['edit'] = array(
389
        'title' => t('Edit'),
390
        'href' => 'file/' . $file->fid . '/edit',
391
        'query' => $destination,
392
      );
393
    }
394
    if (file_entity_access('delete', $file)) {
395
      $operations['delete'] = array(
396
        'title' => t('Delete'),
397
        'href' => 'file/' . $file->fid . '/delete',
398
        'query' => $destination,
399
      );
400
    }
401
    $options[$file->fid]['operations'] = array();
402
    if (count($operations) > 1) {
403
      // Render an unordered list of operations links.
404
      $options[$file->fid]['operations'] = array(
405
        'data' => array(
406
          '#theme' => 'links__file_entity_operations',
407
          '#links' => $operations,
408
          '#attributes' => array('class' => array('links', 'inline')),
409
        ),
410
      );
411
    }
412
    elseif (!empty($operations)) {
413
      // Render the first and only operation as a link.
414
      $link = reset($operations);
415
      $options[$file->fid]['operations'] = array(
416
        'data' => array(
417
          '#type' => 'link',
418
          '#title' => $link['title'],
419
          '#href' => $link['href'],
420
          '#options' => array('query' => $link['query']),
421
        ),
422
      );
423
    }
424
  }
425

    
426
  // Only use a tableselect when the current user is able to perform any
427
  // operations.
428
  if ($admin_access) {
429
    $form['files'] = array(
430
      '#type' => 'tableselect',
431
      '#header' => $header,
432
      '#options' => $options,
433
      '#empty' => t('No files available.'),
434
    );
435
  }
436
  // Otherwise, use a simple table.
437
  else {
438
    $form['files'] = array(
439
      '#theme' => 'table',
440
      '#header' => $header,
441
      '#rows' => $options,
442
      '#empty' => t('No files available.'),
443
    );
444
  }
445

    
446
  $form['pager'] = array('#markup' => theme('pager'));
447
  return $form;
448
}
449

    
450
/**
451
 * Validate file_entity_admin_files form submissions.
452
 *
453
 * Check if any files have been selected to perform the chosen
454
 * 'Update option' on.
455
 */
456
function file_entity_admin_files_validate($form, &$form_state) {
457
  // Error if there are no items to select.
458
  if (!is_array($form_state['values']['files']) || !count(array_filter($form_state['values']['files']))) {
459
    form_set_error('', t('No items selected.'));
460
  }
461
}
462

    
463
/**
464
 * Process file_entity_admin_files form submissions.
465
 *
466
 * Execute the chosen 'Update option' on the selected files.
467
 */
468
function file_entity_admin_files_submit($form, &$form_state) {
469
  $operations = module_invoke_all('file_operations');
470
  $operation = $operations[$form_state['values']['operation']];
471
  // Filter out unchecked files.
472
  $files = array_filter($form_state['values']['files']);
473
  if ($function = $operation['callback']) {
474
    // Add in callback arguments if present.
475
    if (isset($operation['callback arguments'])) {
476
      $args = array_merge(array($files), $operation['callback arguments']);
477
    }
478
    else {
479
      $args = array($files);
480
    }
481
    call_user_func_array($function, $args);
482

    
483
    cache_clear_all();
484
  }
485
  else {
486
    // We need to rebuild the form to go to a second step. For example, to
487
    // show the confirmation form for the deletion of files.
488
    $form_state['rebuild'] = TRUE;
489
  }
490
}
491

    
492
/**
493
 * File entity delete confirmation.
494
 */
495
function file_entity_multiple_delete_confirm($form, &$form_state, $files) {
496
  $form['files'] = array(
497
    '#prefix' => '<ul>',
498
    '#suffix' => '</ul>',
499
    '#tree' => TRUE,
500
  );
501
  // array_filter returns only elements with TRUE values.
502
  foreach ($files as $fid => $value) {
503
    $filename = db_query('SELECT filename FROM {file_managed} WHERE fid = :fid', array(':fid' => $fid))->fetchField();
504
    $form['files'][$fid] = array(
505
      '#type' => 'hidden',
506
      '#value' => $fid,
507
      '#prefix' => '<li>',
508
      '#suffix' => check_plain($filename) . "</li>\n",
509
    );
510
  }
511
  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
512
  $form['#submit'][] = 'file_entity_multiple_delete_confirm_submit';
513
  $confirm_question = format_plural(count($files),
514
                                  'Are you sure you want to delete this item?',
515
                                  'Are you sure you want to delete these items?');
516
  return confirm_form($form,
517
                    $confirm_question,
518
                    'admin/content/file', t('This action cannot be undone.'),
519
                    t('Delete'), t('Cancel'));
520
}
521

    
522
/**
523
 * Submit handler for delete confirmation.
524
 */
525
function file_entity_multiple_delete_confirm_submit($form, &$form_state) {
526
  if ($form_state['values']['confirm']) {
527
    file_delete_multiple(array_keys($form_state['values']['files']));
528
    $count = count($form_state['values']['files']);
529
    watchdog('file_entity', 'Deleted @count files.', array('@count' => $count));
530
    drupal_set_message(format_plural($count, 'Deleted 1 file.', 'Deleted @count files.'));
531
  }
532
  $form_state['redirect'] = 'admin/content/file';
533
}
534

    
535
/**
536
 * Displays the file type admin overview page.
537
 */
538
function file_entity_list_types_page() {
539
  $file_entity_info = entity_get_info('file');
540
  $field_ui = module_exists('field_ui');
541
  $colspan = $field_ui ? 5 : 3;
542
  $header = array(
543
    array('data' => t('Name')),
544
    array('data' => t('Operations'), 'colspan' => $colspan),
545
    array('data' => t('Status')),
546
  );
547
  $rows = array();
548
  $weight = 0;
549
  $types = file_type_load_all(TRUE);
550
  $count = count($types);
551
  foreach ($types as $type) {
552
    $weight++;
553
    $row = array(
554
      array(
555
        'data' => theme('file_entity_file_type_overview',
556
          array(
557
            'label' => $type->label,
558
            'description' => $type->description,
559
          )
560
        ),
561
      ),
562
    );
563
    $path = isset($file_entity_info['bundles'][$type->type]['admin']['real path']) ? $file_entity_info['bundles'][$type->type]['admin']['real path'] : NULL;
564

    
565
    if (empty($type->disabled) && isset($path)) {
566
      $row[] = array('data' => l(t('edit file type'), $path . '/edit'));
567
      if ($field_ui) {
568
        $row[] = array('data' => l(t('manage fields'), $path . '/fields'));
569
        $row[] = array('data' => l(t('manage display'), $path . '/display'));
570
      }
571
      $row[] = array('data' => l(t('manage file display'), $path . '/file-display'));
572
    }
573
    else {
574
      $row += array_fill(1, $colspan - 1, '');
575
    }
576

    
577
    $admin_path = 'admin/structure/file-types/manage/' . $type->type;
578
    switch ($type->ctools_type) {
579
      // Configuration is in code.
580
      case 'Default':
581
        if (!empty($type->disabled)) {
582
          $row[] = l(t('enable'), $admin_path . '/enable');
583
        }
584
        else {
585
          $row[] = l(t('disable'), $admin_path . '/disable');
586
        }
587
        break;
588

    
589
      // Configuration is in DB.
590
      case 'Normal':
591
        if (!empty($type->disabled)) {
592
          $status = l(t('enable'), $admin_path . '/enable');
593
        }
594
        else {
595
          $status = l(t('disable'), $admin_path . '/disable');
596
        }
597
        $row[] = $status . ' | ' . l(t('delete'), $admin_path . '/delete');
598
        break;
599

    
600
      // Configuration is in code, but overridden in DB.
601
      case 'Overridden':
602
        if (!empty($type->disabled)) {
603
          $row[] = l(t('enable'), $admin_path . '/enable');
604
        }
605
        else {
606
          $row[] = l(t('disable'), $admin_path . '/disable') . ' | ' . l(t('revert'), $admin_path . '/revert');
607
        }
608
        break;
609
    }
610

    
611
    if (!empty($type->disabled)) {
612
      $row[] = t('Disabled');
613
      $rows[$weight + $count] = array('data' => $row, 'class' => array('ctools-export-ui-disabled'));
614
    }
615
    else {
616
      $row[] = $type->ctools_type;
617
      $rows[$weight] = array('data' => $row);
618
    }
619
  }
620

    
621
  // Move disabled items to the bottom.
622
  ksort($rows);
623

    
624
  $build['file_type_table'] = array(
625
    '#theme' => 'table',
626
    '#header' => $header,
627
    '#rows' => $rows,
628
    '#empty' => t('No file types available.'),
629
    '#attached' => array(
630
      'css' => array(drupal_get_path('module', 'ctools') . '/css/export-ui-list.css'),
631
    ),
632
  );
633

    
634
  return $build;
635
}
636

    
637
/**
638
 * Form callback; presents file display settings for a given view mode.
639
 */
640
function file_entity_file_display_form($form, &$form_state, $file_type, $view_mode) {
641
  $form['#file_type'] = $file_type->type;
642
  $form['#view_mode'] = $view_mode;
643
  $form['#tree'] = TRUE;
644
  $form['#attached']['js'][] = drupal_get_path('module', 'file_entity') . '/file_entity.admin.js';
645

    
646
  // Retrieve available formatters for this file type and load all configured
647
  // filters for existing text formats.
648
  $formatters = file_info_formatter_types();
649
  foreach ($formatters as $name => $formatter) {
650
    if (!empty($formatter['hidden'])) {
651
      unset($formatters[$name]);
652
    }
653
    if (isset($formatter['mime types'])) {
654
      if (file_entity_match_mimetypes($formatter['mime types'], $file_type->mimetypes)) {
655
        continue;
656
      }
657
      unset($formatters[$name]);
658
    }
659
  }
660
  $current_displays = file_displays_load($file_type->type, $view_mode, TRUE);
661
  foreach ($current_displays as $name => $display) {
662
    $current_displays[$name] = (array) $display;
663
  }
664

    
665
  // Formatter status.
666
  $form['displays']['status'] = array(
667
    '#type' => 'item',
668
    '#title' => t('Enabled displays'),
669
    '#prefix' => '<div id="file-displays-status-wrapper">',
670
    '#suffix' => '</div>',
671
  );
672
  $i = 0;
673
  foreach ($formatters as $name => $formatter) {
674
    $form['displays']['status'][$name] = array(
675
      '#type' => 'checkbox',
676
      '#title' => check_plain($formatter['label']),
677
      '#default_value' => !empty($current_displays[$name]['status']),
678
      '#description' => isset($formatter['description']) ? filter_xss($formatter['description']) : NULL,
679
      '#parents' => array('displays', $name, 'status'),
680
      '#weight' => (isset($formatter['weight']) ? $formatter['weight'] : 0) + ($i / 1000),
681
    );
682
    $i++;
683
  }
684

    
685
  // Formatter order (tabledrag).
686
  $form['displays']['order'] = array(
687
    '#type' => 'item',
688
    '#title' => t('Display precedence order'),
689
    '#theme' => 'file_entity_file_display_order',
690
  );
691
  foreach ($formatters as $name => $formatter) {
692
    $form['displays']['order'][$name]['label'] = array(
693
      '#markup' => check_plain($formatter['label']),
694
    );
695
    $form['displays']['order'][$name]['weight'] = array(
696
      '#type' => 'weight',
697
      '#title' => t('Weight for @title', array('@title' => $formatter['label'])),
698
      '#title_display' => 'invisible',
699
      '#delta' => 50,
700
      '#default_value' => isset($current_displays[$name]['weight']) ? $current_displays[$name]['weight'] : 0,
701
      '#parents' => array('displays', $name, 'weight'),
702
    );
703
    $form['displays']['order'][$name]['#weight'] = $form['displays']['order'][$name]['weight']['#default_value'];
704
  }
705

    
706
  // Formatter settings.
707
  $form['display_settings_title'] = array(
708
    '#type' => 'item',
709
    '#title' => t('Display settings'),
710
  );
711
  $form['display_settings'] = array(
712
    '#type' => 'vertical_tabs',
713
  );
714
  $i = 0;
715
  foreach ($formatters as $name => $formatter) {
716
    if (isset($formatter['settings callback']) && ($function = $formatter['settings callback']) && function_exists($function)) {
717
      $defaults = !empty($formatter['default settings']) ? $formatter['default settings'] : array();
718
      $settings = !empty($current_displays[$name]['settings']) ? $current_displays[$name]['settings'] : array();
719
      $settings += $defaults;
720
      $settings_form = $function($form, $form_state, $settings, $name, $file_type->type, $view_mode);
721
      if (!empty($settings_form)) {
722
        $form['displays']['settings'][$name] = array(
723
          '#type' => 'fieldset',
724
          '#title' => check_plain($formatter['label']),
725
          '#parents' => array('displays', $name, 'settings'),
726
          '#group' => 'display_settings',
727
          '#weight' => (isset($formatter['weight']) ? $formatter['weight'] : 0) + ($i / 1000),
728
        ) + $settings_form;
729
      }
730
    }
731
    $i++;
732
  }
733

    
734
  $form['actions'] = array('#type' => 'actions');
735
  $form['actions']['submit'] = array(
736
    '#type' => 'submit',
737
    '#value' => t('Save configuration'),
738
  );
739

    
740
  return $form;
741
}
742

    
743
/**
744
 * Process file display settings form submissions.
745
 */
746
function file_entity_file_display_form_submit($form, &$form_state) {
747
  $file_type = $form['#file_type'];
748
  $view_mode = $form['#view_mode'];
749
  $displays = isset($form_state['values']['displays']) ? $form_state['values']['displays'] : array();
750
  $displays_original = file_displays_load($file_type, $view_mode, TRUE);
751
  foreach ($displays as $formatter_name => $display) {
752
    $display_original = isset($displays_original[$formatter_name]) ? $displays_original[$formatter_name] : file_display_new($file_type, $view_mode, $formatter_name);
753
    $display += (array) $display_original;
754
    file_display_save((object) $display);
755
  }
756
  drupal_set_message(t('Your settings have been saved.'));
757
}
758

    
759
/**
760
 * Returns HTML for the file type overview page.
761
 *
762
 * Specifically, this returns HTML for a file type label and description.
763
 */
764
function theme_file_entity_file_type_overview($variables) {
765
  return check_plain($variables['label']) . '<div class="description">' . $variables['description'] . '</div>';
766
}
767

    
768
/**
769
 * Returns HTML for a file display's display order table.
770
 */
771
function theme_file_entity_file_display_order($variables) {
772
  $element = $variables['element'];
773

    
774
  $rows = array();
775
  foreach (element_children($element, TRUE) as $name) {
776
    $element[$name]['weight']['#attributes']['class'][] = 'file-display-order-weight';
777
    $rows[] = array(
778
      'data' => array(
779
        drupal_render($element[$name]['label']),
780
        drupal_render($element[$name]['weight']),
781
      ),
782
      'class' => array('draggable'),
783
    );
784
  }
785
  $output = drupal_render_children($element);
786
  $output .= theme('table', array('rows' => $rows, 'attributes' => array('id' => 'file-displays-order')));
787
  drupal_add_tabledrag('file-displays-order', 'order', 'sibling', 'file-display-order-weight', NULL, NULL, TRUE);
788

    
789
  return $output;
790
}
791

    
792
/**
793
 * Form constructor for the file type settings form.
794
 *
795
 * @param object $type
796
 *   The file type.
797
 *
798
 * @see file_entity_file_type_form_validate()
799
 * @see file_entity_file_type_form_submit()
800
 */
801
function file_entity_file_type_form($form, &$form_state, $type = NULL) {
802
  if (!isset($type->type)) {
803
    // This is a new type.
804
    $type = (object) array(
805
      'type' => '',
806
      'label' => '',
807
      'description' => '',
808
      'mimetypes' => array(),
809
    );
810
  }
811
  $form['#file_type'] = $type;
812

    
813
  $form['label'] = array(
814
    '#type' => 'textfield',
815
    '#title' => t('Name'),
816
    '#description' => t('This is the human readable name of the file type.'),
817
    '#required' => TRUE,
818
    '#default_value' => $type->label,
819
  );
820

    
821
  $form['type'] = array(
822
    '#type' => 'machine_name',
823
    '#default_value' => $type->type,
824
    '#maxlength' => 255,
825
    '#disabled' => (bool) $type->type,
826
    '#machine_name' => array(
827
      'exists' => 'file_type_load',
828
      'source' => array('label'),
829
    ),
830
    '#description' => t('A unique machine-readable name for this file type. It must only contain lowercase letters, numbers, and underscores.'),
831
  );
832

    
833
  $form['description'] = array(
834
    '#type' => 'textarea',
835
    '#title' => t('Description'),
836
    '#description' => t('This is the description of the file type.'),
837
    '#default_value' => $type->description,
838
  );
839

    
840
  $form['mimetypes'] = array(
841
    '#type' => 'textarea',
842
    '#title' => t('Mimetypes'),
843
    '#description' => t('Enter one mimetype per line.'),
844
    '#default_value' => implode("\n", $type->mimetypes),
845
  );
846

    
847
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
848
  $mimetypes = file_mimetype_mapping();
849

    
850
  $form['mimetype_mapping'] = array(
851
    '#type' => 'fieldset',
852
    '#title' => t('Mimetype List'),
853
    '#collapsible' => TRUE,
854
    '#collapsed' => TRUE,
855
  );
856
  $form['mimetype_mapping']['mapping'] = array(
857
    '#theme' => 'item_list',
858
    '#items' => $mimetypes['mimetypes'],
859
  );
860

    
861
  $form['actions'] = array('#type' => 'actions');
862

    
863
  $form['actions']['submit'] = array(
864
    '#type' => 'submit',
865
    '#value' => t('Save'),
866
  );
867
  if (!empty($type->type)) {
868
    $form['actions']['delete'] = array(
869
      '#type' => 'submit',
870
      '#value' => t('Delete'),
871
    );
872
  }
873

    
874
  return $form;
875
}
876

    
877
/**
878
 * Form validation handler for file_entity_file_type_form().
879
 *
880
 * @see file_entity_file_type_form_submit()
881
 */
882
function file_entity_file_type_form_validate($form, &$form_state) {
883
  include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
884
  $mimetype_mapping = file_mimetype_mapping();
885

    
886
  $valid_mimetypes = $mimetype_mapping['mimetypes'];
887
  $submitted_mimetypes = array_filter(array_map('trim', explode("\n", $form_state['values']['mimetypes'])));
888

    
889
  $invalid_mimetypes = array();
890
  foreach ($submitted_mimetypes as $mimetype) {
891
    if (!file_entity_match_mimetypes($mimetype, $valid_mimetypes)) {
892
      $invalid_mimetypes[] = $mimetype;
893
    }
894
  }
895

    
896
  foreach ($invalid_mimetypes as $mimetype) {
897
    form_set_error('mimetypes', t('The mimetype %mimetype is not a valid mimetype.', array('%mimetype' => $mimetype)));
898
  }
899
}
900

    
901
/**
902
 * Form submission handler for file_entity_file_type_form().
903
 *
904
 * @see file_entity_file_type_form_validate()
905
 */
906
function file_entity_file_type_form_submit($form, &$form_state) {
907
  if (!empty($form['#file_type']->type)) {
908
    $type = file_type_load($form['#file_type']->type);
909
  }
910
  else {
911
    $type = (object) array(
912
      'type' => $form_state['values']['type'],
913
    );
914
  }
915
  if ($form_state['values']['op'] == t('Delete')) {
916
    $form_state['redirect'] = 'admin/structure/file-types/manage/' . $type->type . '/delete';
917
    return;
918
  }
919
  $type->label = $form_state['values']['label'];
920
  $type->description = $form_state['values']['description'];
921
  $type->mimetypes = array_filter(array_map('trim', explode("\n", $form_state['values']['mimetypes'])));
922

    
923
  file_type_save($type);
924

    
925
  drupal_set_message(t('The file type %type has been updated.', array('%type' => $type->label)));
926
  $form_state['redirect'] = 'admin/structure/file-types';
927
}
928

    
929

    
930
/**
931
 * Menu callback; disable a single file type.
932
 */
933
function file_entity_type_enable_confirm($form, &$form_state, $type) {
934
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
935
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
936
  $message = t('Are you sure you want to enable the file type %type?', array('%type' => $type->label));
937
  return confirm_form($form, $message, 'admin/structure/file-types', '', t('Enable'));
938
}
939

    
940

    
941
/**
942
 * Process file type disable confirm submissions.
943
 */
944
function file_entity_type_enable_confirm_submit($form, &$form_state) {
945
  file_type_enable($form_state['values']['type']);
946
  $t_args = array('%label' => $form_state['values']['label']);
947
  drupal_set_message(t('The file type %label has been enabled.', $t_args));
948
  watchdog('file_entity', 'Enabled file type %label.', $t_args, WATCHDOG_NOTICE);
949
  $form_state['redirect'] = 'admin/structure/file-types';
950
  return;
951
}
952

    
953

    
954
/**
955
 * Menu callback; disable a single file type.
956
 */
957
function file_entity_type_disable_confirm($form, &$form_state, $type) {
958
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
959
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
960

    
961
  $message = t('Are you sure you want to disable the file type %type?', array('%type' => $type->label));
962
  $caption = '';
963

    
964
  $num_files = db_query("SELECT COUNT(*) FROM {file_managed} WHERE type = :type", array(':type' => $type->type))->fetchField();
965
  if ($num_files) {
966
    $caption .= '<p>' . format_plural($num_files, '%type is used by 1 file on
967
      your site. If you disable this file type, you will not be able to edit
968
      the %type file and it may not display correctly.', '%type is used by
969
      @count files on your site. If you remove %type, you will not be able to
970
      edit the %type file and it may not display correctly.',
971
    array('%type' => $type->label)) . '</p>';
972
  }
973

    
974
  return confirm_form($form, $message, 'admin/structure/file-types', $caption, t('Disable'));
975
}
976

    
977

    
978
/**
979
 * Process file type disable confirm submissions.
980
 */
981
function file_entity_type_disable_confirm_submit($form, &$form_state) {
982
  file_type_disable($form_state['values']['type']);
983
  $t_args = array('%label' => $form_state['values']['label']);
984
  drupal_set_message(t('The file type %label has been disabled.', $t_args));
985
  watchdog('file_entity', 'Disabled file type %label.', $t_args, WATCHDOG_NOTICE);
986
  $form_state['redirect'] = 'admin/structure/file-types';
987
  return;
988
}
989

    
990

    
991
/**
992
 * Menu callback; revert a single file type.
993
 */
994
function file_entity_type_revert_confirm($form, &$form_state, $type) {
995
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
996
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
997
  $message = t('Are you sure you want to revert the file type %type?', array('%type' => $type->label));
998
  return confirm_form($form, $message, 'admin/structure/file-types', '', t('Revert'));
999
}
1000

    
1001

    
1002
/**
1003
 * Process file type delete confirm submissions.
1004
 */
1005
function file_entity_type_revert_confirm_submit($form, &$form_state) {
1006
  // @NOTE deleting the file_type from the DB actually reverts it to code.
1007
  file_type_delete($form_state['values']['type']);
1008
  $t_args = array('%label' => $form_state['values']['label']);
1009
  drupal_set_message(t('The file type %label has been reverted.', $t_args));
1010
  watchdog('file_entity', 'Reverted file type %label.', $t_args, WATCHDOG_NOTICE);
1011
  $form_state['redirect'] = 'admin/structure/file-types';
1012
  return;
1013
}
1014

    
1015

    
1016
/**
1017
 * Menu callback; delete a single file type.
1018
 */
1019
function file_entity_type_delete_confirm($form, &$form_state, $type) {
1020
  $form['type'] = array('#type' => 'value', '#value' => $type->type);
1021
  $form['label'] = array('#type' => 'value', '#value' => $type->label);
1022

    
1023
  $message = t('Are you sure you want to delete the file type %type?', array('%type' => $type->label));
1024
  $caption = '';
1025

    
1026
  $num_files = db_query("SELECT COUNT(*) FROM {file_managed} WHERE type = :type", array(':type' => $type->type))->fetchField();
1027
  if ($num_files) {
1028
    $caption .= '<p>' . format_plural($num_files, '%type is used by 1 file on your site. If you remove this file type, you will not be able to edit the %type file and it may not display correctly.', '%type is used by @count pieces of file on your site. If you remove %type, you will not be able to edit the %type file and it may not display correctly.', array('%type' => $type->label)) . '</p>';
1029
  }
1030

    
1031
  $caption .= '<p>' . t('This action cannot be undone.') . '</p>';
1032

    
1033
  return confirm_form($form, $message, 'admin/structure/file-types', $caption, t('Delete'));
1034
}
1035

    
1036
/**
1037
 * Process file type delete confirm submissions.
1038
 */
1039
function file_entity_type_delete_confirm_submit($form, &$form_state) {
1040
  file_type_delete($form_state['values']['type']);
1041

    
1042
  $t_args = array('%label' => $form_state['values']['label']);
1043
  drupal_set_message(t('The file type %label has been deleted.', $t_args));
1044
  watchdog('file_entity', 'Deleted file type %label.', $t_args, WATCHDOG_NOTICE);
1045

    
1046
  $form_state['redirect'] = 'admin/structure/file-types';
1047
  return;
1048
}
1049

    
1050
/**
1051
 * Form callback for file_entity settings.
1052
 */
1053
function file_entity_settings_form($form, &$form_state) {
1054
  $form['file_entity_max_filesize'] = array(
1055
    '#type' => 'textfield',
1056
    '#title' => t('Maximum upload size'),
1057
    '#default_value' => variable_get('file_entity_max_filesize', ''),
1058
    '#description' => t('Enter a value like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes) in order to restrict the allowed file size. If left empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current max limit <strong>%limit</strong>).', array('%limit' => format_size(file_upload_max_size()))),
1059
    '#size' => 10,
1060
    '#element_validate' => array('_file_generic_settings_max_filesize'),
1061
  );
1062

    
1063
  $form['file_entity_default_allowed_extensions'] = array(
1064
    '#type' => 'textfield',
1065
    '#title' => t('Default allowed file extensions'),
1066
    '#default_value' => variable_get('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp mp3 mov mp4 m4a m4v mpeg avi ogg oga ogv weba webp webm'),
1067
    '#description' => t('Separate extensions with a space or comma and do not include the leading dot.'),
1068
    '#maxlength' => NULL,
1069
  );
1070

    
1071
  $form['file_entity_alt'] = array(
1072
    '#type' => 'textfield',
1073
    '#title' => t('Alt attribute'),
1074
    '#description' => t('The text to use as value for the <em>img</em> tag <em>alt</em> attribute.'),
1075
    '#default_value' => variable_get('file_entity_alt', '[file:field_file_image_alt_text]'),
1076
  );
1077
  $form['file_entity_title'] = array(
1078
    '#type' => 'textfield',
1079
    '#title' => t('Title attribute'),
1080
    '#description' => t('The text to use as value for the <em>img</em> tag <em>title</em> attribute.'),
1081
    '#default_value' => variable_get('file_entity_title', '[file:field_file_image_title_text]'),
1082
  );
1083

    
1084
  // Provide default token values.
1085
  if (module_exists('token')) {
1086
    $form['token_help'] = array(
1087
      '#theme' => 'token_tree',
1088
      '#token_types' => array('file'),
1089
      '#dialog' => TRUE,
1090
    );
1091
    $form['file_entity_alt']['#description'] .= t('This field supports tokens.');
1092
    $form['file_entity_title']['#description'] .= t('This field supports tokens.');
1093
  }
1094
  $form['file_upload_wizard'] = array(
1095
    '#type' => 'fieldset',
1096
    '#title' => t('File upload wizard'),
1097
    '#collapsible' => TRUE,
1098
    '#collapsed' => FALSE,
1099
    '#description' => t('Configure the steps available when uploading a new file.'),
1100
  );
1101
  $form['file_upload_wizard']['file_entity_file_upload_wizard_skip_file_type'] = array(
1102
    '#type' => 'checkbox',
1103
    '#title' => t('Skip filetype selection.'),
1104
    '#default_value' => variable_get('file_entity_file_upload_wizard_skip_file_type', FALSE),
1105
    '#description' => t('The file type selection step is only available if the uploaded file falls into two or more file types. If this step is skipped, files with no available file type or two or more file types will not be assigned a file type.'),
1106
  );
1107
  $form['file_upload_wizard']['file_entity_file_upload_wizard_skip_scheme'] = array(
1108
    '#type' => 'checkbox',
1109
    '#title' => t('Skip scheme selection.'),
1110
    '#default_value' => variable_get('file_entity_file_upload_wizard_skip_scheme', FALSE),
1111
    '#description' => t('The scheme selection step is only available if two or more file destinations, such as public local files served by the webserver and private local files served by Drupal, are available. If this step is skipped, files will automatically be saved using the default download method.'),
1112
  );
1113
  $form['file_upload_wizard']['file_entity_file_upload_wizard_skip_fields'] = array(
1114
    '#type' => 'checkbox',
1115
    '#title' => t('Skip available fields.'),
1116
    '#default_value' => variable_get('file_entity_file_upload_wizard_skip_fields', FALSE),
1117
    '#description' => t('The field selection step is only available if the file type the file belongs to has any available fields. If this step is skipped, any fields on the file will be left blank.'),
1118
  );
1119

    
1120
  return system_settings_form($form);
1121
}