File Coverage

blib/lib/Icon/Theme/Helper.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Icon::Theme::Helper;
2              
3 1     1   21876 use warnings;
  1         3  
  1         28  
4 1     1   5 use strict;
  1         2  
  1         30  
5 1     1   414 use Icon::Theme::Index::Parse;
  0            
  0            
6              
7             =head1 NAME
8              
9             Icon::Theme::Helper - Helps locating icon files.
10              
11             =head1 VERSION
12              
13             Version 0.0.0
14              
15             =cut
16              
17             our $VERSION = '0.0.0';
18              
19              
20             =head1 SYNOPSIS
21              
22             use Icon::Theme::Helper;
23              
24             my $iconhelper = Icon::Theme::Helper->new();
25              
26             =head1 METHODS
27              
28             =head2 new
29              
30             This initializes the object.
31              
32             =head3 args hash ref
33              
34             =head4 alwaysIncludeHicolor
35              
36             Always include the hicolor theme.
37              
38             This defaults to '1'.
39              
40             =head4 alwaysIncludeGnome
41              
42             Always include the gnome theme.
43              
44             This defaults to '1'.
45              
46             =head4 dir
47              
48             This is the icon dir to use.
49              
50             If this is not defined, the first directory
51             found below will be used.
52              
53             /usr/local/share/icons
54             /usr/share/icons
55              
56             =head4 maxSize
57              
58             This is the maximum size to use.
59              
60             If undefined, there is no upper
61             size limit.
62              
63             =head4 minSize
64              
65             This is the minimum size to use.
66              
67             If undefined, there is no lower
68             size limit.
69              
70             =head4 scalable
71              
72             Wether or not to use scalable icons.
73              
74             If not defined, this defaults to 1.
75              
76             =head4 size
77              
78             This is the prefered size to use.
79              
80             If this is not defined, '32' is used.
81              
82             =head4 skip
83              
84             A list of inherited themes to skip.
85              
86             =head4 theme
87              
88             This is the icon theme to use.
89              
90             If none is specified, 'hicolor' is used.
91              
92             =cut
93              
94             sub new{
95             my %args;
96             if (defined( $_[1] )) {
97             %args=%{$_[1]};
98             }
99             my $method='new';
100              
101             my $self={error=>undef, perror=>undef, errorString=>'', module=>'Icon-Theme-Helper'};
102             bless $self;
103              
104             #try to automatically detect the directory to use if none is specified
105             if (!defined( $args{dir} )) {
106             if (-d '/usr/local/share/icons/') {
107             $self->{dir}='/usr/local/share/icons/';
108             }else {
109             if (-d '/usr/share/icons/') {
110             $self->{dir}='/usr/share/icons/';
111             }
112             }
113              
114             #error if no directory can be found
115             if (!defined( $self->{dir} )) {
116             $self->{error}=1;
117             $self->{perror}=1;
118             $self->{errorString}='No directory specified and one could not be automatically located';
119             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
120             return $self;
121             }
122              
123             }else {
124             $self->{dir}=$args{dir};
125              
126             #error if the specified directory can not be found
127             if (!defined( $self->{dir} )) {
128             $self->{error}=2;
129             $self->{perror}=1;
130             $self->{errorString}='The specified directory, "'.$self->{dir}.'", does not exist';
131             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
132             return $self;
133             }
134             }
135              
136              
137             #get the theme to use
138             if (!defined( $args{theme} )) {
139             $self->{theme}='hicolor';
140             }else {
141             $self->{theme}=$args{theme};
142             }
143              
144             if (! -d $self->{dir}.'/'.$self->{theme} ) {
145             $self->{error}=3;
146             $self->{perror}=1;
147             $self->{errorString}='The specified directory, "'.$self->{dir}.'", does not exist';
148             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
149             return $self;
150             }
151              
152             if (! -f $self->{dir}.'/'.$self->{theme}.'/index.theme' ) {
153             $self->{error}=4;
154             $self->{perror}=1;
155             $self->{errorString}='The specified theme, "'.$self->{theme}.'", is not a Freedesktop.org compliant icon theme';
156             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
157             return $self;
158             }
159              
160             #holds the required themes
161             $self->{themes}={};
162              
163             #read the default theme
164             $self->{themes}{$self->{theme}}=Icon::Theme::Index::Parse->new_from_file($self->{dir}.'/'.$self->{theme}.'/index.theme');
165             if ($self->{themes}{$self->{theme}}->{error}) {
166             $self->{error}=5;
167             $self->{perror}=1;
168             $self->{errorString}='Failed to load the index for the theme "'.$self->{theme}.'"';
169             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
170             return $self;
171             }
172              
173             #gets the themes it inherits
174             my @inherits=$self->{themes}{$self->{theme}}->inherits;
175              
176             #skips over any thing it is told to be skipped
177              
178             #builds a order array of themes to check
179             my @themeOrder=( $self->{theme} );
180             push(@themeOrder, @inherits);
181              
182             #this holds a list of items that have been processed
183             my %processed;
184             $processed{$self->{theme}}=1; #adds the starting theme to the list to avoid it
185              
186             #processes each one...
187             my $int=1; #we start at 1 as the first item in the themeOrder list is the theme that was used
188             while (defined( $themeOrder[$int] )) {
189             my $theme=$themeOrder[$int];
190              
191             #only process it if we have now already
192             if (!defined( $processed{$theme} )) {
193             #only parse it if the index file exists
194             my $index=$self->{dir}.'/'.$theme.'/index.theme';
195             if (-f $index) {
196             my $parsedTheme=Icon::Theme::Index::Parse->new_from_file($index);
197             #process this theme if it did not error
198             if (! $parsedTheme->{error} ) {
199             $self->{themes}{$theme}=$parsedTheme;
200             #
201             push(@themeOrder, $theme);
202             #push the inherited stuff onto this stack
203             @inherits=$self->{themes}{$theme}->inherits;
204             push(@themeOrder, @inherits);
205            
206             #mark as processed so it is not done again
207             $processed{$theme}=1
208             }
209             }
210             }
211              
212             $int++;
213             }
214              
215             #include hicolor if needed
216             if (!defined( $args{alwaysIncludeHicolor} )) {
217             $args{alwaysIncludeHicolor}=1;
218             }
219             if ($args{alwaysIncludeHicolor}) {
220             #only proceed if it has not been processed already
221             if (!defined( $processed{'hicolor'} )) {
222             #only proceed if the index file exists
223             if (-f $self->{dir}.'/hicolor/index.theme' ) {
224             my $parsedTheme=Icon::Theme::Index::Parse->new_from_file( $self->{dir}.'/hicolor/index.theme' );
225             #only add it if there was no error
226             if (! $parsedTheme->{error} ) {
227             $self->{themes}{'hicolor'}=$parsedTheme;
228             #push this theme into the order
229             push(@themeOrder, 'hicolor');
230             #push the inherited stuff onto this stack
231             @inherits=$self->{themes}{'hicolor'}->inherits;
232             push(@themeOrder, @inherits);
233            
234             #mark as processed so it is not done again
235             $processed{'hicolor'}=1
236             }
237             }
238             }
239             }
240              
241             #include gnome if needed
242             if (!defined( $args{alwaysIncludeGnome} )) {
243             $args{alwaysIncludeGnome}=1;
244             }
245             if ($args{alwaysIncludeGnome}) {
246             #only proceed if it has not been processed already
247             if (!defined( $processed{'gnome'} )) {
248             #only proceed if the index file exists
249             if (-f $self->{dir}.'/gnome/index.theme' ) {
250             my $parsedTheme=Icon::Theme::Index::Parse->new_from_file( $self->{dir}.'/gnome/index.theme' );
251             #only add it if there was no error
252             if (! $parsedTheme->{error} ) {
253             $self->{themes}{'gnome'}=$parsedTheme;
254             #push this theme into the order
255             push(@themeOrder, 'gnome');
256             #push the inherited stuff onto this stack
257             @inherits=$self->{themes}{'gnome'}->inherits;
258             push(@themeOrder, @inherits);
259            
260             #mark as processed so it is not done again
261             $processed{'gnome'}=1
262             }
263             }
264             }
265             }
266            
267             #cleans the order list of redundant items
268             my @cleanThemeOrder;
269             my %cleanedThemes; #used for check if a theme has been cleaned or not
270             $int=0;
271             while ( defined( $themeOrder[$int] ) ) {
272             my $theme=$themeOrder[$int];
273              
274             if (!defined( $cleanedThemes{ $theme } )) {
275             push(@cleanThemeOrder, $theme);
276             $cleanedThemes{$theme}=1;
277             }
278              
279             $int++;
280             }
281              
282             #saves the theme order
283             $self->{order}=\@cleanThemeOrder;
284              
285             #saves the min, max, preferred size, and scalable boolean
286             if (defined( $args{minsize} )) {
287             $self->{minSize}=$args{minsize};
288             }
289             if (defined( $args{maxSize} )) {
290             $self->{maxSize}=$args{maxSize};
291             }
292             if (defined( $args{size} )) {
293             $self->{size}=$args{size};
294             }else {
295             $self->{size}='32';
296             }
297             if (defined($args{scalable} )) {
298             $self->{scalable}=$args{scalable};
299             }else {
300             $self->{scalable}='1';
301             }
302              
303             return $self;
304             }
305              
306             =head2 getIcon
307              
308             This returns the icon file.
309              
310             The first arguement is the context and the second is the icon name.
311              
312             my $iconFile=$iconhelper->getIcon('Places', 'desktop');
313              
314             =cut
315              
316             sub getIcon{
317             my $self=$_[0];
318             my $context=$_[1];
319             my $name=$_[2];
320             my $method='getIcon';
321              
322             #blanks any previous errors
323             $self->errorblank;
324             if ($self->{error}) {
325             return undef;
326             }
327              
328             #error if there is no context specified
329             if (!defined( $context )) {
330             $self->{error}=6;
331             $self->{errorString}='No context defined';
332             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
333             return $self;
334             }
335              
336             #error if there is no name specified
337             if (!defined( $name )) {
338             $self->{error}=7;
339             $self->{errorString}='No icon name defined';
340             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
341             return $self;
342             }
343              
344             #process each theme till we find a int
345             my $themeInt=0;
346             while (defined( $self->{order}[$themeInt] )) {
347             my $theme=$self->{order}[$themeInt];
348              
349             #check each directory
350             my $dirInt=0;
351             if (defined( $self->{themes}{$theme} )) {
352             my @dirs=$self->{themes}{$theme}->directories;
353             if (!$self->{themes}{$theme}->{error}) {
354             while (defined( $dirs[$dirInt] )) {
355             my $dircontext=$self->{themes}{$theme}->dirContext( $dirs[$dirInt] );
356             if (defined($dircontext) && ($context eq $dircontext)) {
357             my $check=1; #default if true;
358            
359             my $size=$self->{themes}{$theme}->dirSize( $dirs[$dirInt] );
360            
361             #checks if it needs to check minSize
362             if (defined($self->{minSize}) && defined($size)) {
363             #don't check this directory if the size is to small
364             if ( $self->{minSize} > $size ) {
365             $check=0;
366             }
367             }
368            
369             #checks if it needs to check maxSize
370             if (defined($self->{maxSize}) && defined($size) && $check ) {
371             #don't check this directory if the size is to large
372             if ( $self->{maxSize} < $size ) {
373             $check=0;
374             }
375             }
376            
377             #don't check the directory depending on the scalable preference
378             if (!$self->{scalable}) {
379             $check=0;
380             }
381            
382             #check if the specified icon exists or not
383             if ($check) {
384             my $basename=$self->{dir}."/".$theme.'/'.$dirs[$dirInt].'/'.$name.'.';
385            
386             #checks for a svg if scalable
387             if ($self->{scalable}) {
388             if (-f $basename.'svg') {
389             return $basename.'svg'
390             }
391             }
392            
393             #checks for a potential xpm icon
394             if (-f $basename.'xpm') {
395             return $basename.'xpm'
396             }
397            
398             #checks for a potential png icon
399             if (-f $basename.'png') {
400             return $basename.'png'
401             }
402             }
403             }
404            
405            
406             $dirInt++;
407             }
408             }
409             }
410              
411             $themeInt++;
412             }
413              
414             #not found
415             return undef;
416             }
417              
418             =head2 getMimeTypeIcon
419              
420             This searches and feches a MIME type icon.
421              
422             One arguement is taken and it is the MIME type.
423              
424             $iconFile=$iconhelper->getMimeTypeIcon('application/pdf');
425              
426             =cut
427              
428             sub getMimeTypeIcon{
429             my $self=$_[0];
430             my $mimetype=$_[1];
431             my $method='getMimeTypeIcon';
432              
433             #blanks any previous errors
434             $self->errorblank;
435             if ($self->{error}) {
436             return undef;
437             }
438              
439             if (!defined($mimetype)) {
440             $self->{error}=8;
441             $self->{errorString}='No MIME type defined';
442             warn($self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString});
443             return $self;
444             }
445              
446             #replace the / in the mimetype with a -
447             $mimetype=~s/\//\-/;
448              
449             #declare it here for simplicity
450             my $icon;
451              
452             #try a regular mime type
453             $icon=$self->getIcon('MimeTypes', $mimetype);
454             if (defined($icon)) {
455             return $icon;
456             }
457              
458             #sees if there is a gnome mimetype
459             $icon=$self->getIcon('MimeTypes', 'gnome-mime-'.$mimetype);
460             if (defined($icon)) {
461             return $icon;
462             }
463              
464             #if it has spreadsheet in it, check for a regular spreadsheet
465             if ($mimetype =~ /spreadsheet/) {
466             $icon=$self->getIcon('MimeType', 'spreadsheet');
467             if (defined($icon)) {
468             return $icon;
469             }
470             }
471              
472             #if it has document in it, check for a regular document
473             if ($mimetype =~ /document/) {
474             $icon=$self->getIcon('MimeTypes', 'document');
475             if (defined($icon)) {
476             return $icon;
477             }
478             }
479             if ($mimetype =~ /document/) {
480             $icon=$self->getIcon('MimeTypes', 'x-office-document');
481             if (defined($icon)) {
482             return $icon;
483             }
484             }
485              
486             #tries to find a icon for a zip file
487             if ($mimetype =~ /zip/) {
488             $icon=$self->getIcon('MimeTypes', 'zip');
489             if (defined($icon)) {
490             return $icon;
491             }
492             }
493              
494             #tries a generic one if it is a tar ball
495             if ($mimetype =~ /tar/) {
496             $icon=$self->getIcon('MimeTypes', 'tar');
497             if (defined($icon)) {
498             return $icon;
499             }
500             }
501              
502             #tries a generic one if it is video
503             if ($mimetype =~ /video/) {
504             $icon=$self->getIcon('MimeTypes', 'video');
505             if (defined($icon)) {
506             return $icon;
507             }
508             }
509              
510             #tries a generic one if it is a html file
511             if ($mimetype =~ /html/) {
512             $icon=$self->getIcon('MimeTypes', 'text-html');
513             if (defined($icon)) {
514             return $icon;
515             }
516             }
517             if ($mimetype =~ /html/) {
518             $icon=$self->getIcon('MimeTypes', 'html');
519             if (defined($icon)) {
520             return $icon;
521             }
522             }
523              
524             #tries a generic one for a template
525             if ($mimetype =~ /template/) {
526             $icon=$self->getIcon('MimeTypes', 'text-x-generic-template');
527             if (defined($icon)) {
528             return $icon;
529             }
530             }
531              
532             #tries a generic one for a addressbook
533             if ($mimetype =~ /addressbook/) {
534             $icon=$self->getIcon('MimeTypes', 'stock_addressbook');
535             if (defined($icon)) {
536             return $icon;
537             }
538             }
539             if ($mimetype =~ /addressbook/) {
540             $icon=$self->getIcon('MimeTypes', 'addressbook');
541             if (defined($icon)) {
542             return $icon;
543             }
544             }
545             if ($mimetype =~ /addressbook/) {
546             $icon=$self->getIcon('MimeTypes', 'x-office-address-book');
547             if (defined($icon)) {
548             return $icon;
549             }
550             }
551              
552             #checks it for a calendar
553             if ($mimetype =~ /calendar/) {
554             $icon=$self->getIcon('MimeTypes', 'calendar');
555             if (defined($icon)) {
556             return $icon;
557             }
558             }
559             if ($mimetype =~ /calendar/) {
560             $icon=$self->getIcon('MimeTypes', 'stock_calendar');
561             if (defined($icon)) {
562             return $icon;
563             }
564             }
565             if ($mimetype =~ /calendar/) {
566             $icon=$self->getIcon('MimeTypes', 'x-office-calendar');
567             if (defined($icon)) {
568             return $icon;
569             }
570             }
571              
572             #try it for images
573             if ($mimetype =~ /image/) {
574             $icon=$self->getIcon('MimeTypes', 'image');
575             if (defined($icon)) {
576             return $icon;
577             }
578             }
579             if ($mimetype =~ /image/) {
580             $icon=$self->getIcon('MimeTypes', 'image-x-generic');
581             if (defined($icon)) {
582             return $icon;
583             }
584             }
585              
586             #gets it for a RPM
587             if ($mimetype =~ /rpm$/) {
588             $icon=$self->getIcon('MimeTypes', 'rpm');
589             if (defined($icon)) {
590             return $icon;
591             }
592             }
593              
594             #tries a generic one for a text file
595             if ($mimetype =~ /text/) {
596             $icon=$self->getIcon('MimeTypes', 'txt');
597             if (defined($icon)) {
598             return $icon;
599             }
600             }
601              
602             #try unknown before finally returning undef
603             $icon=$self->getIcon('MimeTypes', 'unknown');
604             if (defined($icon)) {
605             return $icon;
606             }
607              
608             #if we get here we did not find one
609             return undef;
610             }
611              
612             =head1 ERROR METHODS
613              
614             =head2 error
615              
616             This fetches any current errors.
617              
618             A return of undef, false, indicates no error is present.
619              
620             if($iconhelper->error){
621             warn("Error!");
622             }
623              
624             =cut
625              
626             sub error{
627             return $_[0]->{error};
628             }
629              
630             =head2 errorblank
631              
632             This blanks any previous error.
633              
634             This is a internal function.
635              
636             =cut
637              
638             sub errorblank{
639             my $self=$_[0];
640              
641             if ($self->{perror}) {
642             warn($self->{module}.' errorblank: A permanent error is set');
643             }
644              
645             $self->{error}=undef;
646             $self->{errorString}=undef;
647              
648             return 1;
649             }
650              
651              
652             =head1 ERROR CODES
653              
654             =head2 1
655              
656             No directory specified and one could not be automatically located.
657              
658             =head2 2
659              
660             The specified directory does not exist.
661              
662             =head2 3
663              
664             The specified theme does not exist.
665              
666             =head2 4
667              
668             The theme is not a Freedesktop.org compliant theme.
669              
670             =head2 5
671              
672             Parsing the index for the specified config failed.
673              
674             =head2 6
675              
676             No context specified.
677              
678             =head2 7
679              
680             No icon name specified.
681              
682             =head2 8
683              
684             No MIME type specified.
685              
686             =head1 AUTHOR
687              
688             Zane C. Bowers, C<< >>
689              
690             =head1 BUGS
691              
692             Please report any bugs or feature requests to C, or through
693             the web interface at L. I will be notified, and then you'll
694             automatically be notified of progress on your bug as I make changes.
695              
696              
697              
698              
699             =head1 SUPPORT
700              
701             You can find documentation for this module with the perldoc command.
702              
703             perldoc Icon::Theme::Helper
704              
705              
706             You can also look for information at:
707              
708             =over 4
709              
710             =item * RT: CPAN's request tracker
711              
712             L
713              
714             =item * AnnoCPAN: Annotated CPAN documentation
715              
716             L
717              
718             =item * CPAN Ratings
719              
720             L
721              
722             =item * Search CPAN
723              
724             L
725              
726             =back
727              
728              
729             =head1 ACKNOWLEDGEMENTS
730              
731              
732             =head1 COPYRIGHT & LICENSE
733              
734             Copyright 2009 Zane C. Bowers, all rights reserved.
735              
736             This program is free software; you can redistribute it and/or modify it
737             under the same terms as Perl itself.
738              
739              
740             =cut
741              
742             1; # End of Icon::Theme::Helper