82dd8942630e1e7387988b4c339615f05c6ee30a
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_iconworks.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains class for icon generation in the backend
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
32 * XHTML compliant
33 *
34 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 85: class t3lib_iconWorks
42 * 100: function getIconImage($table,$row=array(),$backPath,$params='',$shaded=FALSE)
43 * 118: function getIcon($table,$row=array(),$shaded=FALSE)
44 * 264: function skinImg($backPath,$src,$wHattribs='',$outputMode=0)
45 *
46 * SECTION: Other functions
47 * 353: function makeIcon($iconfile,$mode, $user, $protectSection,$absFile,$iconFileName_stateTagged)
48 * 475: function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h)
49 * 505: function imagecreatefrom($file)
50 * 522: function imagemake($im, $path)
51 *
52 * TOTAL FUNCTIONS: 7
53 * (This index is automatically created/updated by the extension "extdeveval")
54 *
55 */
56
57
58
59
60
61
62
63
64
65
66 /**
67 * Icon generation, backend
68 * This library has functions that returns - and if necessary creates - the icon for an element in TYPO3
69 *
70 * Expects global vars:
71 * - $BACK_PATH
72 * - PATH_typo3
73 * - $TCA, $PAGES_TYPES
74 *
75 *
76 * Notes:
77 * These functions are strongly related to the interface of TYPO3.
78 * The class is included in eg. init.php
79 * ALL functions called without making a class instance, eg. "t3lib_iconWorks::getIconImage()"
80 *
81 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
82 * @package TYPO3
83 * @subpackage t3lib
84 */
85 final class t3lib_iconWorks {
86
87 protected static $tcaSpriteIconNames = array();
88
89 public static $fileSpriteIconNames = array(
90 'htm' => 'mimetype-text-htm',
91 'html' => 'mimetype-text-htm',
92 'css' => 'mimetype-text-css',
93 'js' => 'mimetype-text-js',
94 'csv' => 'mimetype-text-csv',
95 'xml' => 'mimetype-text-xml',
96 'php' => 'mimetype-text-php',
97 'php6' => 'mimetype-text-php',
98 'php5' => 'mimetype-text-php',
99 'php4' => 'mimetype-text-php',
100 'php3' => 'mimetype-text-php',
101 'inc' => 'mimetype-text-php',
102 'ts' => 'mimetype-text-ts',
103 'txt' => 'mimetype-text-text',
104 'class' => 'mimetype-text-text',
105 'tmpl' => 'mimetype-text-text',
106 'jpg' => 'mimetype-media-image-jpg',
107 'jpeg' => 'mimetype-media-image-jpg',
108 'gif' => 'mimetype-media-image-gif',
109 'png' => 'mimetype-media-image-png',
110 'bmp' => 'mimetype-media-image-bmp',
111 'tif' => 'mimetype-media-image',
112 'tga' => 'mimetype-media-image',
113 'psd' => 'mimetype-media-image',
114 'eps' => 'mimetype-media-image',
115 'avi' => 'mimetype-media-video-avi',
116 'mpg' => 'mimetype-media-video',
117 'mpeg' => 'mimetype-media-video',
118 'mov' => 'mimetype-media-video',
119 'wav' => 'mimetype-media-audio',
120 'mp3' => 'mimetype-media-audio',
121 'mid' => 'mimetype-media-audio',
122 'swf' => 'mimetype-media-flash',
123 'swa' => 'mimetype-media-flash',
124 'exe' => 'mimetype-executable-executable',
125 'com' => 'mimetype-executable-executable',
126 't3x' => 'mimetype-compressed-t3x',
127 't3d' => 'mimetype-compressed-t3d',
128 'zip' => 'mimetype-compressed-compressed',
129 'tgz' => 'mimetype-compressed-compressed',
130 'gz' => 'mimetype-compressed-compressed',
131 'pdf' => 'mimetype-word-pdf',
132 'doc' => 'mimetype-word-word',
133 'sxw' => 'mimetype-word-word',
134 'rtf' => 'mimetype-word-word',
135 'xls' => 'mimetype-spreadsheet-spreadsheet',
136 'sxc' => 'mimetype-spreadsheet-spreadsheet',
137 'ttf' => 'mimetype-font-font',
138 'ppt' => 'mimetype-presentation-presentation',
139 'mount' => 'apps-filetree-mount',
140 'folder' => 'apps-filetree-folder-default',
141 'default' => 'mimetype-other-other'
142 );
143
144 /**
145 * Returns an icon image tag, 18x16 pixels, based on input information.
146 * This function is recommended to use in your backend modules.
147 * Usage: 60
148 *
149 * @param string The table name
150 * @param array The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
151 * @param string The backpath to the main TYPO3 directory (relative path back to PATH_typo3)
152 * @param string Additional attributes for the image tag
153 * @param boolean If set, the icon will be grayed/shaded
154 * @return string <img>-tag
155 * @see getIcon()
156 */
157 public static function getIconImage($table, $row = array(), $backPath, $params = '', $shaded = FALSE) {
158 $str = '<img'.t3lib_iconWorks::skinImg($backPath, t3lib_iconWorks::getIcon($table, $row, $shaded), 'width="18" height="16"').(trim($params)?' '.trim($params):'');
159 if (!stristr($str, 'alt="')) {
160 $str.=' alt=""';
161 }
162 $str.=' />';
163 return $str;
164 }
165
166 /**
167 * Creates the icon for input table/row
168 * Returns filename for the image icon, relative to PATH_typo3
169 * Usage: 24
170 *
171 * @param string The table name
172 * @param array The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
173 * @param boolean If set, the icon will be grayed/shaded
174 * @return string Icon filename
175 * @see getIconImage()
176 */
177 public static function getIcon($table, $row = array(), $shaded = FALSE) {
178 global $TCA, $PAGES_TYPES, $ICON_TYPES;
179
180 // Flags:
181 $doNotGenerateIcon = $GLOBALS['TYPO3_CONF_VARS']['GFX']['noIconProc']; // If set, the icon will NOT be generated with GDlib. Rather the icon will be looked for as [iconfilename]_X.[extension]
182 $doNotRenderUserGroupNumber = TRUE; // If set, then the usergroup number will NOT be printed unto the icon. NOTICE. the icon is generated only if a default icon for groups is not found... So effectively this is ineffective...
183
184 // Shadow:
185 if ($TCA[$table]['ctrl']['versioningWS']) {
186 switch((int)$row['t3ver_state']) {
187 case 1:
188 return 'gfx/i/shadow_hide.png';
189 break;
190 case 2:
191 return 'gfx/i/shadow_delete.png';
192 break;
193 case 3:
194 return 'gfx/i/shadow_moveto_plh.png';
195 break;
196 case 4:
197 return 'gfx/i/shadow_moveto_pointer.png';
198 break;
199 }
200 }
201
202 // First, find the icon file name. This can depend on configuration in TCA, field values and more:
203 if ($table=='pages') {
204 // @TODO: RFC #7370: doktype 2&5 are deprecated since TYPO3 4.2-beta1
205 if ($row['nav_hide'] && ($row['doktype']==1||$row['doktype']==2)) $row['doktype'] = 5; // Workaround to change the icon if "Hide in menu" was set
206
207 if (!$iconfile = $PAGES_TYPES[$row['doktype']]['icon']) {
208 $iconfile = $PAGES_TYPES['default']['icon'];
209 }
210 if ($row['module'] && $ICON_TYPES[$row['module']]['icon']) {
211 $iconfile = $ICON_TYPES[$row['module']]['icon'];
212 }
213 } else {
214 if (!$iconfile = $TCA[$table]['ctrl']['typeicons'][$row[$TCA[$table]['ctrl']['typeicon_column']]]) {
215 $iconfile = (($TCA[$table]['ctrl']['iconfile']) ? $TCA[$table]['ctrl']['iconfile'] : $table.'.gif');
216 }
217 }
218
219 // Setting path of iconfile if not already set. Default is "gfx/i/"
220 if (!strstr($iconfile, '/')) {
221 $iconfile = 'gfx/i/'.$iconfile;
222 }
223
224 // Setting the absolute path where the icon should be found as a file:
225 if (substr($iconfile, 0, 3)=='../') {
226 $absfile = PATH_site.substr($iconfile, 3);
227 } else {
228 $absfile = PATH_typo3.$iconfile;
229 }
230
231 // Initializing variables, all booleans except otherwise stated:
232 $hidden = FALSE;
233 $timing = FALSE;
234 $futuretiming = FALSE;
235 $user = FALSE; // In fact an integer value...
236 $deleted = FALSE;
237 $protectSection = FALSE; // Set, if a page-record (only pages!) has the extend-to-subpages flag set.
238 $noIconFound = $row['_NO_ICON_FOUND'] ? TRUE : FALSE;
239 // + $shaded which is also boolean!
240
241 // Icon state based on "enableFields":
242 if (is_array($TCA[$table]['ctrl']['enablecolumns'])) {
243 $enCols = $TCA[$table]['ctrl']['enablecolumns'];
244 // If "hidden" is enabled:
245 if ($enCols['disabled']) { if ($row[$enCols['disabled']]) { $hidden = TRUE; }}
246 // If a "starttime" is set and higher than current time:
247 if ($enCols['starttime']) {
248 if ($GLOBALS['EXEC_TIME'] < intval($row[$enCols['starttime']])) {
249 $timing = TRUE;
250 // ...And if "endtime" is NOT set:
251 if (intval($row[$enCols['endtime']]) == 0) {
252 $futuretiming = TRUE;
253 }
254 }
255 }
256 // If an "endtime" is set:
257 if ($enCols['endtime']) {
258 if (intval($row[$enCols['endtime']]) > 0) {
259 if (intval($row[$enCols['endtime']]) < $GLOBALS['EXEC_TIME']) {
260 $timing = TRUE; // End-timing applies at this point.
261 } else {
262 $futuretiming = TRUE; // End-timing WILL apply in the future for this element.
263 }
264 }
265 }
266 // If a user-group field is set:
267 if ($enCols['fe_group']) {
268 $user = $row[$enCols['fe_group']];
269 if ($user && $doNotRenderUserGroupNumber) $user = 100; // Limit for user number rendering!
270 }
271 }
272
273 // If "deleted" flag is set (only when listing records which are also deleted!)
274 if ($col = $row[$TCA[$table]['ctrl']['delete']]) {
275 $deleted = TRUE;
276 }
277 // Detecting extendToSubpages (for pages only)
278 if ($table=='pages' && $row['extendToSubpages'] && ($hidden || $timing || $futuretiming || $user)) {
279 $protectSection = TRUE;
280 }
281
282 // If ANY of the booleans are set it means we have to alter the icon:
283 if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
284 $flags = '';
285 $string = '';
286 if ($deleted) {
287 $string = 'deleted';
288 $flags = 'd';
289 } elseif ($noIconFound) { // This is ONLY for creating icons with "?" on easily...
290 $string = 'no_icon_found';
291 $flags = 'x';
292 } else {
293 if ($hidden) $string.='hidden';
294 if ($timing) $string.='timing';
295 if (!$string && $futuretiming) {
296 $string = 'futuretiming';
297 }
298
299 $flags.=
300 ($hidden ? 'h' : '').
301 ($timing ? 't' : '').
302 ($futuretiming ? 'f' : '').
303 ($user ? 'u' : '').
304 ($protectSection ? 'p' : '').
305 ($shaded ? 's' : '');
306 }
307
308 // Create tagged icon file name:
309 $iconFileName_stateTagged = preg_replace('/.([[:alnum:]]+)$/', '__'.$flags.'.\1', basename($iconfile));
310
311 // Check if tagged icon file name exists (a tagget icon means the icon base name with the flags added between body and extension of the filename, prefixed with underscore)
312 if (@is_file(dirname($absfile) . '/' . $iconFileName_stateTagged) || @is_file($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . '/' . dirname($iconfile) . '/' . $iconFileName_stateTagged)) { // Look for [iconname]_xxxx.[ext]
313 return dirname($iconfile).'/'.$iconFileName_stateTagged;
314 } elseif ($doNotGenerateIcon) { // If no icon generation can be done, try to look for the _X icon:
315 $iconFileName_X = preg_replace('/.([[:alnum:]]+)$/', '__x.\1', basename($iconfile));
316 if (@is_file(dirname($absfile).'/'.$iconFileName_X)) {
317 return dirname($iconfile).'/'.$iconFileName_X;
318 } else {
319 return 'gfx/i/no_icon_found.gif';
320 }
321 } else { // Otherwise, create the icon:
322 $theRes = t3lib_iconWorks::makeIcon($GLOBALS['BACK_PATH'].$iconfile, $string, $user, $protectSection, $absfile, $iconFileName_stateTagged);
323 return $theRes;
324 }
325 } else {
326 return $iconfile;
327 }
328 }
329
330 /**
331 * Returns the src=... for the input $src value OR any alternative found in $TBE_STYLES['skinImg']
332 * Used for skinning the TYPO3 backend with an alternative set of icons
333 * Usage: 336
334 *
335 * @param string Current backpath to PATH_typo3 folder
336 * @param string Icon file name relative to PATH_typo3 folder
337 * @param string Default width/height, defined like 'width="12" height="14"'
338 * @param integer Mode: 0 (zero) is default and returns src/width/height. 1 returns value of src+backpath, 2 returns value of w/h.
339 * @return string Returns ' src="[backPath][src]" [wHattribs]'
340 * @see skinImgFile()
341 */
342 public static function skinImg($backPath, $src, $wHattribs = '', $outputMode = 0) {
343
344 static $cachedSkinImages = array();
345
346 $imageId = md5($backPath . $src . $wHattribs . $outputMode);
347
348 if (isset($cachedSkinImages[$imageId])) {
349 return $cachedSkinImages[$imageId];
350 }
351 // Setting source key. If the icon is refered to inside an extension, we homogenize the prefix to "ext/":
352 $srcKey = preg_replace('/^(\.\.\/typo3conf\/ext|sysext|ext)\//', 'ext/', $src);
353 #if ($src!=$srcKey)debug(array($src, $srcKey));
354
355 // LOOKING for alternative icons:
356 if ($GLOBALS['TBE_STYLES']['skinImg'][$srcKey]) { // Slower or faster with is_array()? Could be used.
357 list($src, $wHattribs) = $GLOBALS['TBE_STYLES']['skinImg'][$srcKey];
358 } elseif ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']) { // Otherwise, test if auto-detection is enabled:
359
360 // Search for alternative icon automatically:
361 $fExt = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['forceFileExtension'];
362 $scaleFactor = ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] ? $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] : 1); // Scaling factor
363 $lookUpName = ($fExt ? preg_replace('/\.[[:alnum:]]+$/', '', $srcKey) . '.' . $fExt : $srcKey); // Set filename to look for
364
365 if ($fExt && !@is_file($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName)) {
366 // fallback to original filename if icon with forced extension doesn't exists
367 $lookUpName = $srcKey;
368 }
369 // If file is found:
370 if (@is_file($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'].$lookUpName)) { // If there is a file...
371 $iInfo = @getimagesize($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName); // Get width/height:
372
373 // Set $src and $wHattribs:
374 $src = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'] . $lookUpName;
375 $wHattribs = 'width="' . round($iInfo[0] * $scaleFactor) . '" height="' . round($iInfo[1] * $scaleFactor) . '"';
376 }
377
378 // In any case, set currect src / wHattrib - this way we make sure that an entry IS found next time we hit the function,
379 // regardless of whether it points to a alternative icon or just the current.
380 $GLOBALS['TBE_STYLES']['skinImg'][$srcKey] = array($src, $wHattribs); // Set default...
381 }
382
383 // DEBUG: This doubles the size of all icons - for testing/debugging:
384 # if (preg_match('/^width="([0-9]+)" height="([0-9]+)"$/', $wHattribs, $reg)) $wHattribs='width="'.($reg[1]*2).'" height="'.($reg[2]*2).'"';
385
386
387 // rendering disabled (greyed) icons using _i (inactive) as name suffix ("_d" is already used)
388 $matches = array();
389 $srcBasename = basename($src);
390 if (preg_match('/(.*)_i(\....)$/', $srcBasename, $matches)) {
391 $temp_path = dirname(PATH_thisScript) . '/';
392 if (!@is_file($temp_path . $backPath . $src)) {
393 $srcOrg = preg_replace('/_i' . preg_quote($matches[2]) . '$/', $matches[2], $src);
394 $src = t3lib_iconWorks::makeIcon($backPath . $srcOrg, 'disabled', 0, false, $temp_path . $backPath . $srcOrg, $srcBasename);
395 }
396 }
397
398
399 // Return icon source/wHattributes:
400 $output = '';
401 switch($outputMode) {
402 case 0:
403 $output = ' src="' . $backPath . $src . '" ' . $wHattribs;
404 break;
405 case 1:
406 $output = $backPath . $src;
407 break;
408 case 2:
409 $output = $wHattribs;
410 break;
411 }
412
413 $cachedSkinImages[$imageId] = $output;
414 return $output;
415 }
416
417
418
419
420
421
422
423
424
425
426
427 /***********************************
428 *
429 * Other functions
430 *
431 ***********************************/
432
433 /**
434 * Creates the icon file for the function getIcon()
435 *
436 * @param string Original unprocessed Icon file, relative path to PATH_typo3
437 * @param string Mode string, eg. "deleted" or "futuretiming" determining how the icon will look
438 * @param integer The number of the fe_group record uid if applicable
439 * @param boolean Flag determines if the protected-section icon should be applied.
440 * @param string Absolute path to file from which to create the icon.
441 * @param string The filename that this icon should have had, basically [icon base name]_[flags].[extension] - used for part of temporary filename
442 * @return string Filename relative to PATH_typo3
443 * @access private
444 */
445 public static function makeIcon($iconfile, $mode, $user, $protectSection, $absFile, $iconFileName_stateTagged) {
446 $iconFileName = 'icon_'.t3lib_div::shortMD5($iconfile.'|'.$mode.'|-'.$user.'|'.$protectSection).'_'.$iconFileName_stateTagged.'.'.($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']?'png':'gif');
447 $mainpath = '../typo3temp/'.$iconFileName;
448 $path = PATH_site.'typo3temp/'.$iconFileName;
449
450
451 if (file_exists(PATH_typo3.'icons/'.$iconFileName)) { // Returns if found in typo3/icons/
452 return 'icons/'.$iconFileName;
453 } elseif (file_exists($path)) { // Returns if found in ../typo3temp/icons/
454 return $mainpath;
455 } else { // Makes icon:
456 if (file_exists($absFile)) {
457 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
458
459 // Create image pointer, if possible
460 $im = t3lib_iconworks::imagecreatefrom($absFile);
461 if ($im<0) return $iconfile;
462
463 // Converting to gray scale, dimming the icon:
464 if (($mode=='disabled') OR ($mode!='futuretiming' && $mode!='no_icon_found' && !(!$mode && $user))) {
465 for ($c = 0; $c<ImageColorsTotal($im); $c++) {
466 $cols = ImageColorsForIndex($im, $c);
467 $newcol = round(($cols['red']+$cols['green']+$cols['blue'])/3);
468 $lighten = ($mode=='disabled') ? 2.5 : 2;
469 $newcol = round(255-((255-$newcol)/$lighten));
470 ImageColorSet($im, $c, $newcol, $newcol, $newcol);
471 }
472 }
473 // Applying user icon, if there are access control on the item:
474 if ($user) {
475 if ($user < 100) { // Apply user number only if lower than 100
476 $black = ImageColorAllocate($im, 0, 0, 0);
477 imagefilledrectangle($im, 0, 0, (($user>10)?9:5), 8, $black);
478
479 $white = ImageColorAllocate($im, 255, 255, 255);
480 imagestring($im, 1, 1, 1, $user, $white);
481 }
482
483 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_group.gif');
484 if ($ol_im<0) return $iconfile;
485
486 t3lib_iconworks::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
487 }
488 // Applying overlay based on mode:
489 if ($mode) {
490 unset($ol_im);
491 switch($mode) {
492 case 'deleted':
493 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_deleted.gif');
494 break;
495 case 'futuretiming':
496 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_timing.gif');
497 break;
498 case 'timing':
499 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_timing.gif');
500 break;
501 case 'hiddentiming':
502 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_hidden_timing.gif');
503 break;
504 case 'no_icon_found':
505 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_no_icon_found.gif');
506 break;
507 case 'disabled':
508 // is already greyed - nothing more
509 $ol_im = 0;
510 break;
511 case 'hidden':
512 default:
513 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_hidden.gif');
514 break;
515 }
516 if ($ol_im<0) return $iconfile;
517 if ($ol_im) {
518 t3lib_iconworks::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
519 }
520 }
521 // Protect-section icon:
522 if ($protectSection) {
523 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_sub5.gif');
524 if ($ol_im<0) return $iconfile;
525 t3lib_iconworks::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
526 }
527
528 // Create the image as file, destroy GD image and return:
529 @t3lib_iconWorks::imagemake($im, $path);
530 t3lib_div::gif_compress($path, 'IM');
531 ImageDestroy($im);
532 return $mainpath;
533 } else {
534 return $iconfile;
535 }
536 } else {
537 return $GLOBALS['BACK_PATH'].'gfx/fileicons/default.gif';
538 }
539 }
540 }
541
542 /**
543 * The necessity of using this function for combining two images if GD is version 2 is that
544 * GD2 cannot manage to combine two indexed-color images without totally spoiling everything.
545 * In class.t3lib_stdgraphic this was solved by combining the images onto a first created true color image
546 * However it has turned out that this method will not work if the indexed png-files contains transparency.
547 * So I had to turn my attention to ImageMagick - my 'enemy of death'.
548 * And so it happend - ImageMagick is now used to combine my two indexed-color images with transparency. And that works.
549 * Of course it works only if ImageMagick is able to create valid png-images - which you cannot be sure of with older versions (still 5+)
550 * The only drawback is (apparently) that IM creates true-color png's. The transparency of these will not be shown by MSIE on windows at this time (although it's straight 0%/100% transparency!) and the file size may be larger.
551 *
552 * For parameters, see PHP function "imagecopyresized()"
553 *
554 * @param pointer see PHP function "imagecopyresized()"
555 * @param pointer see PHP function "imagecopyresized()"
556 * @param integer see PHP function "imagecopyresized()"
557 * @param integer see PHP function "imagecopyresized()"
558 * @param integer see PHP function "imagecopyresized()"
559 * @param integer see PHP function "imagecopyresized()"
560 * @param integer see PHP function "imagecopyresized()"
561 * @param integer see PHP function "imagecopyresized()"
562 * @param integer see PHP function "imagecopyresized()"
563 * @param integer see PHP function "imagecopyresized()"
564 * @return void
565 * @access private
566 */
567 public static function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) {
568 imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h);
569 }
570
571 /**
572 * Create new image pointer from input file (either gif/png, in case the wrong format it is converted by t3lib_div::read_png_gif())
573 *
574 * @param string Absolute filename of the image file from which to start the icon creation.
575 * @return mixed If success, image pointer, otherwise "-1"
576 * @access private
577 * @see t3lib_div::read_png_gif
578 */
579 public static function imagecreatefrom($file) {
580 $file = t3lib_div::read_png_gif($file, $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']);
581 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
582 return $file ? imagecreatefrompng($file) : -1;
583 } else {
584 return $file ? imagecreatefromgif($file) : -1;
585 }
586 }
587
588 /**
589 * Write the icon in $im pointer to $path
590 *
591 * @param pointer Pointer to GDlib image resource
592 * @param string Absolute path to the filename in which to write the icon.
593 * @return void
594 * @access private
595 */
596 public static function imagemake($im, $path) {
597 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
598 @ImagePng($im, $path);
599 } else {
600 @ImageGif($im, $path);
601 }
602 }
603
604
605 /**********************************************
606 * SPRITE ICON API
607 *
608 * The Sprite Icon API helps you to quickly get the HTML for any icon you want
609 * this is typically wrapped in a <span> tag with corresponding CSS classes that
610 * will be responsible for the
611 *
612 * There are three ways to use this API:
613 *
614 * 1) for any given TCA record
615 * $spriteIconHtml = t3lib_iconWorks::getSpriteIconForRecord('pages', $row);
616 *
617 * 2) for any given file
618 * $spriteIconHtml = t3lib_iconWorks::getSpriteIconForFile('myimage.png');
619 *
620 * 3) for any other icon you know the name
621 * $spriteIconHtml = t3lib_iconWorks::getSpriteIcon('actions-document-open');
622 *
623 **********************************************/
624
625 /**
626 * This generic method is used throughout the TYPO3 Backend to show icons in any variation which are not
627 * bound to any file type (see getSpriteIconForFile) or database record (see getSpriteIconForRecord)
628 *
629 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
630 * already to have a pre-defined background image, and the correct background-position to show
631 * the necessary icon.
632 *
633 * @param string $iconName the name of the icon to fetch
634 * @param array $options an associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
635 * @param array $overlays an associative array with the icon-name as key, and the options for this overlay as an array again (see the parameter $options again)
636 * @return string the full HTML tag (usually a <span>)
637 * @access public
638 */
639 public static function getSpriteIcon($iconName, $options = array(), $overlays = array()) {
640 $innerHtml = (isset($options['html']) ? $options['html'] : '');
641 $tagName = (isset($options['tagName']) ? $options['tagName'] : 'span');
642
643 // deal with the overlays
644 if (count($overlays)) {
645 foreach ($overlays as $overlayIconName => $overlayOptions) {
646 $overlayOptions['html'] = $innerHtml;
647 $overlayOptions['class'] = (isset($overlayOptions['class']) ? $overlayOptions['class'] . ' ': '') . 't3-icon-overlay';
648 $innerHtml = self::getSpriteIcon($overlayIconName, $overlayOptions);
649 }
650 }
651
652 // create the CSS class
653 $options['class'] = self::getSpriteIconClasses($iconName) . (isset($options['class']) ? ' ' . $options['class'] : '');
654
655 unset($options['html']);
656 unset($options['tagName']);
657 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
658 }
659
660
661 /**
662 * This method is used throughout the TYPO3 Backend to show icons for a file type
663 *
664 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
665 * already to have a pre-defined background image, and the correct background-position to show
666 * the necessary icon.
667 *
668 * @param string $fileExtension the name of the icon to fetch, can be a file extension, full file path or one of the special keywords "folder" or "mount"
669 * @param array $options an associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
670 * @return string the full HTML tag (usually a <span>)
671 * @access public
672 */
673 public static function getSpriteIconForFile($fileExtension, $options = array()) {
674 $innerHtml = (isset($options['html']) ? $options['html'] : '');
675 $tagName = (isset($options['tagName']) ? $options['tagName'] : 'span');
676
677 // create the CSS class
678 $options['class'] = self::mapFileExtensionToSpriteIconClass($fileExtension) . (isset($options['class']) ? ' ' . $options['class'] : '');
679
680 unset($options['html']);
681 unset($options['tagName']);
682 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
683 }
684
685
686 /**
687 * Generates the spriteicon name for a given path or fileExtension
688 * usually called from getSpriteIconForFile
689 *
690 * @param string fileExtension can be jpg, gif etc, but also be 'mount' or 'folder', but can also be a full path which will be resolved then
691 * @return string the string of the CSS class, see t3lib_iconworks::$fileSpriteIconNames
692 */
693 public static function mapFileExtensionToSpriteIconClass($fileExtension) {
694
695 // if the file is a whole file with name etc (mainly, if it has a "." or a "/"),
696 // then it is checked whether it is a valid directory
697 if (strpos($fileExtension, '.') !== FALSE || strpos($fileExtension, '/') !== FALSE) {
698
699 // check if it is a directory
700 $filePath = dirname(t3lib_div::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $fileExtension;
701 $path = t3lib_div::resolveBackPath($filePath);
702 if (is_dir($path) || substr($fileExtension, -1) === '/' || substr($fileExtension, -1) === '\\') {
703 $fileExtension = 'folder';
704 } else if (($pos = strrpos($fileExtension, '.')) !== FALSE) {
705 $fileExtension = strtolower(substr($fileExtension, $pos + 1));
706 } else {
707 $fileExtension = 'default';
708 }
709 }
710
711 // if the file extension is not valid
712 // then use the default one
713 if (!isset(self::$fileSpriteIconNames[$fileExtension])) {
714 $fileExtension = 'default';
715 }
716 $iconName = self::$fileSpriteIconNames[$fileExtension];
717 return self::getSpriteIconClasses($iconName);
718 }
719
720
721 /**
722 * This method is used throughout the TYPO3 Backend to show icons for a DB record
723 *
724 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
725 * already to have a pre-defined background image, and the correct background-position to show
726 * the necessary icon.
727 *
728 * @param string $table the TCA table name
729 * @param array $row the DB record of the TCA table
730 * @param array $options an associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
731 * @return string the full HTML tag (usually a <span>)
732 * @access public
733 */
734 public static function getSpriteIconForRecord($table, $row, $options = array()) {
735 $innerHtml = (isset($options['html']) ? $options['html'] : '');
736 $tagName = (isset($options['tagName']) ? $options['tagName'] : 'span');
737
738 // overlay this record icon with the status of the row
739 $overlaySpriteIconName = self::mapRecordOverlayToSpriteIconName($table, $row);
740 if ($overlaySpriteIconName) {
741 $overlayOptions = array(
742 'html' => $innerHtml,
743 'class' => 't3-icon-overlay'
744 );
745 $innerHtml = self::getSpriteIcon($overlaySpriteIconName, $overlayOptions);
746 }
747
748 // fetch the name for the CSS class, based on the $row
749 $options['class'] = self::mapRecordTypeToSpriteIconClass($table, $row) . (isset($options['class']) ? ' ' . $options['class'] : '');
750
751 unset($options['html']);
752 unset($options['tagName']);
753 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
754 }
755
756
757 /**
758 * this helper functions looks up the column that is used for the type of
759 * the chosen TCA table. And then fetches the corresponding class
760 * based on the chosen iconsprite class in this TCA
761 * The TCA looks up
762 * - [ctrl][typeicon_column]
763 * -
764 * This method solely takes care of the type of this record, not any
765 * statuses, used for overlays.
766 *
767 * see t3lib/stddb/tables.php for an example with the TCA table "pages"
768 *
769 * @param string $table the TCA table
770 * @param array $row the selected record
771 * @return string the CSS class for the sprite icon of that DB record
772 * @access private
773 **/
774 protected static function mapRecordTypeToSpriteIconClass($table, $row) {
775 self::buildTcaSpriteIconNames();
776 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_column'])) {
777 $column = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
778
779 $recordType = $row[$column];
780
781 // workaround to give nav_hide pages a complete different icon
782 // although it's not a separate doctype
783 if ($table === 'pages' && $row['nav_hide']) {
784 $recordType .= '-hideinmenu';
785 }
786
787 $iconName = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$recordType];
788 if (!$iconName && in_array('tcarecords-' . $table . '-' . $recordType, self::$tcaSpriteIconNames)) {
789 $iconName = 'tcarecords-' . $table . '-' . $recordType;
790 }
791 } else {
792 $iconName = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][0];
793 if (!$iconName && in_array('tcarecords-' . $table . '-default', self::$tcaSpriteIconNames)) {
794 $iconName = 'tcarecords-' . $table . '-default';
795 }
796 }
797 return self::getSpriteIconClasses(($iconName ? $iconName : 'status-status-icon-missing'));
798 }
799
800
801 /**
802 * this helper functions checks if the DB record ($row) has any special status
803 * based on the TCA settings like hidden, starttime etc, and then returns a specific
804 * Sprite icon class for the overlay of this DB record
805 * This method solely takes care of the overlay of this record, not any type
806 *
807 * Please note that this only returns one overlay, one status, that is prioritized
808 * by $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayPriorities']
809 * We wanted to not have these icons blown over by tons of overlays, so this is limited
810 * to just one.
811 *
812 * see t3lib/config_default.php for the default options, you will find
813 * $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayNames'] that shows
814 * the list of CSS classes that will be used for the sprites, mapped to the statuses here
815 *
816 * @param string $table the TCA table
817 * @param array $row the selected record
818 * @return string the CSS class for the sprite icon of that DB record
819 * @access private
820 */
821 protected static function mapRecordOverlayToSpriteIconName($table, $row) {
822 $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
823
824 // Calculate for a given record the actual visibility at the moment
825 $status = array(
826 'hidden' => FALSE,
827 'starttime' => FALSE,
828 'endtime' => FALSE,
829 'futureendtime' => FALSE,
830 'fe_group' => FALSE,
831 'deleted' => FALSE,
832 'protectedSection' => FALSE,
833 'nav_hide' => ($row['nav_hide'] ? TRUE : FALSE),
834 'noIconFound' => ($row['_NO_ICON_FOUND'] ? TRUE : FALSE),
835 );
836
837 // Icon state based on "enableFields":
838 if (is_array($tcaCtrl['enablecolumns'])) {
839 $enCols = $tcaCtrl['enablecolumns'];
840 // If "hidden" is enabled:
841 if ($tcaCtrl['enablecolumns']['disabled'] && $row[$tcaCtrl['enablecolumns']['disabled']]) {
842 $status['hidden'] = TRUE;
843 }
844 // If a "starttime" is set and higher than current time:
845 if ($tcaCtrl['enablecolumns']['starttime'] && $GLOBALS['EXEC_TIME'] < intval($row[$tcaCtrl['enablecolumns']['starttime']])) {
846 $status['starttime'] = TRUE;
847 }
848
849 // If an "endtime" is set
850 if ($tcaCtrl['enablecolumns']['endtime']) {
851 if (intval($row[$tcaCtrl['enablecolumns']['endtime']]) > 0) {
852 if (intval($row[$tcaCtrl['enablecolumns']['endtime']]) < $GLOBALS['EXEC_TIME']) {
853 // End-timing applies at this point.
854 $status['endtime'] = TRUE;
855 } else {
856 // End-timing WILL apply in the future for this element.
857 $status['futureendtime'] = TRUE;
858 }
859 }
860 }
861 // If a user-group field is set
862 if ($tcaCtrl['enablecolumns']['fe_group'] && $row[$tcaCtrl['enablecolumns']['fe_group']]) {
863 $status['fe_group'] = TRUE;
864 }
865 }
866
867 // If "deleted" flag is set (only when listing records which are also deleted!)
868 if ($row[$tcaCtrl['delete']]) {
869 $status['deleted'] = TRUE;
870 }
871
872 // Detecting extendToSubpages (for pages only)
873 if ($table == 'pages' && $row['extendToSubpages'] && ($status['hidden'] || $status['starttime'] || $status['endtime'] || $status['futureendtime'] || $status['fe_group'])) {
874 $status['protectedSection'] = TRUE;
875 }
876
877
878 // now only show the status with the highest priority
879 $priorities = $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayPriorities'];
880
881 $iconName = '';
882 foreach ($priorities as $priority) {
883 if ($status[$priority]) {
884 $iconName = $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayNames'][$priority];
885 break;
886 }
887 }
888
889 return $iconName;
890 }
891
892
893
894 /**
895 * generic method to create the final CSS classes based on the sprite icon name
896 * with the base class and splits the name into parts
897 * is usually called by the methods that are responsible for fetching the names
898 * out of the file name, or the record type
899 *
900 * @param string $name iconname like 'actions-document-new'
901 * @return string a list of all CSS classes needed for the HTML tag
902 * @access public
903 */
904 public static function getSpriteIconClasses($iconName) {
905 $cssClasses = $baseCssClass = 't3-icon';
906 $parts = explode('-', $iconName);
907
908 if (count($parts) > 1) {
909 // will be something like "t3-icon-actions"
910 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0]);
911 // will be something like "t3-icon-actions-document"
912 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0] . '-' . $parts[1]);
913 // will be something like "t3-icon-document-new"
914 $cssClasses .= ' ' . ($baseCssClass . '-' . substr($iconName, strlen($parts[0]) + 1));
915 }
916 return $cssClasses;
917 }
918
919
920 /**
921 * low level function that generates the HTML tag for the sprite icon
922 * is usually called by the three API classes (getSpriteIcon, getSpriteIconForFile, getSpriteIconForRecord)
923 * it does not care about classes or anything else, but just plainly builds the HTML tag
924 *
925 * @param array $tagAttributes an associative array of additional tagAttributes for the HTML tag
926 * @param string $innerHtml (optional) the content within the tag, a "&nbsp;" by default
927 * @param string $tagName (optional) the name of the HTML element that should be used (span by default)
928 */
929 protected static function buildSpriteHtmlIconTag($tagAttributes, $innerHtml = '&nbsp;', $tagName = 'span') {
930 $attributes = '';
931 foreach ($tagAttributes as $attribute => $value) {
932 $attributes .= ' ' . htmlspecialchars($attribute) . '="' . htmlspecialchars($value) . '"';
933 }
934 return '<' . $tagName . $attributes . '>' . $innerHtml . '</' . $tagName . '>';
935 }
936
937
938
939 /**
940 * this method creates SpriteIcon names for all tables in TCA (including their possible type-icons)
941 * where there is no "typeicon_classes" of this TCA table ctrl section and caches the result to the TYPO3 registry
942 *
943 * Note: This method is just preliminary and will be extracted in the future to go to t3lib_spriteGenerator
944 *
945 * @return void
946 */
947 protected static function buildTcaSpriteIconNames() {
948 // if the data is already loaded during this request,
949 // there is nothing to do
950 if (!count(self::$tcaSpriteIconNames)) {
951
952 // step one: check with registry if an update is needed
953 $registry = t3lib_div::makeInstance('t3lib_Registry');
954 $storedHash = $registry->get('core', 'tcaSpriteIconNamesTcaHash', '');
955 $TCAtables = array_keys($GLOBALS['TCA']);
956 $currentHash = md5(serialize($TCAtables)) . 'A';
957
958 // the fileName is prefixed with since the concatenator orders files per name
959 $cssTcaFile = PATH_site . 'typo3temp/sprites/zextensions.css';
960
961 // if update would be needed or file does not exist
962 if ($storedHash != $currentHash || !file_exists($cssTcaFile)) {
963
964 $styleSheetTemplate = '
965 .t3-icon-###TABLE###-###TYPE### {
966 background-position: 0px 0px !important;
967 background-image: url(\'###IMAGE###\') !important;
968 }
969 ';
970
971 // delete old tempFiles
972 @unlink($cssTcaFile);
973
974 // contains the content of the CSS file
975 $styleSheetData = '';
976
977 // backpath from the stylesheet file ($cssTcaFile) to typo3 dir
978 // in order to set the background-image URL paths correct
979 $iconPath = '../../' . TYPO3_mainDir;
980
981 // path (relative from typo3 dir) for skin-Images
982 if (isset($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'])) {
983 $skinPath = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'];
984 } else {
985 $skinPath = '';
986 }
987
988 // check every table in the TCA, if an icon is needed
989 foreach ($TCAtables as $tableName) {
990
991 // this method is only needed for TCA tables where
992 // typeicon_classes are not configured
993 if (!is_array($GLOBALS['TCA'][$tableName]['ctrl']['typeicon_classes'])) {
994 $tcaCtrl = $GLOBALS['TCA'][$tableName]['ctrl'];
995
996 $template = str_replace('###TABLE###', $tableName, $styleSheetTemplate);
997
998 // adding the default Icon (without types)
999 if (isset($tcaCtrl['iconfile'])) {
1000 // in CSS wie need a path relative to the css file
1001 // [TCA][ctrl][iconfile] defines icons without path info to reside in /gfx/i/
1002 if (strpos($tcaCtrl['iconfile'], '/') !== FALSE) {
1003 $icon = $tcaCtrl['iconfile'];
1004 } else {
1005 $icon = $skinPath .'gfx/i/' . $tcaCtrl['iconfile'];
1006 }
1007
1008 $icon = t3lib_div::resolveBackPath($iconPath . $icon);
1009
1010 // saving default icon
1011 $stylesString = str_replace('###TYPE###', 'default', $template);
1012 $stylesString = str_replace('###IMAGE###', $icon, $stylesString);
1013 $styleSheetData .= $stylesString;
1014 self::$tcaSpriteIconNames[] = 'tcarecords-'. $tableName . '-default';
1015 }
1016
1017 // if records types are available, register them
1018 if (isset($tcaCtrl['typeicon_column']) && is_array($tcaCtrl['typeicons'])) {
1019 foreach ($tcaCtrl['typeicons'] as $type => $icon) {
1020
1021 // in CSS wie need a path relative to the css file
1022 // [TCA][ctrl][iconfile] defines icons without path info to reside in /gfx/i/
1023 if (strpos($icon, '/') === FALSE) {
1024 $icon = $skinPath .'gfx/i/' . $icon;
1025 }
1026
1027 $icon = t3lib_div::resolveBackPath($iconPath . $icon);
1028 $stylesString = str_replace('###TYPE###', $type, $template);
1029 $stylesString = str_replace('###IMAGE###', $icon, $stylesString);
1030 // saving type icon
1031 $styleSheetData .= $stylesString;
1032 self::$tcaSpriteIconNames[] = 'tcarecords-' . $tableName . '-' . $type;
1033 }
1034 }
1035 }
1036 }
1037
1038 // cache results in the CSS file
1039 t3lib_div::writeFileToTypo3tempDir($cssTcaFile, $styleSheetData);
1040
1041 // update registry
1042 $registry->set('core', 'tcaSpriteIconNames', serialize(self::$tcaSpriteIconNames));
1043 $registry->set('core', 'tcaSpriteIconNamesTcaHash', $currentHash);
1044
1045 } else {
1046 // if no update is needed just load the old results
1047 self::$tcaSpriteIconNames = unserialize($registry->get('core', 'tcaSpriteIconNames'));
1048 }
1049 }
1050 }
1051 }
1052 ?>