source: subversion/applications/share/map-icons/update_icons.pl @ 4220

Last change on this file since 4220 was 4193, checked in by joerg, 13 years ago

rename jp to japan

  • Property svn:executable set to *
File size: 17.0 KB
Line 
1#!/usr/bin/perl
2#####################################################################
3#
4#  This script handles the XML-Files for the POI-Types in gpsdrive.
5#  It has to be run from the data directory.
6
7#  Default actions, when no options are given:
8#  - Create basic XML-File if none is available
9#  - Search icons directories for PNG files
10#  - Add those files as new POI-Types if they are not yet existent
11#  - Create overview.html from the XML-File to show all
12#    available poi_types and icons.
13#
14#####################################################################
15#
16#  Scheme for the entries (only poi_type relevant elements are shown):
17#
18#  <rule>
19#    <condition k="poi" v="$NAME" />
20#    <scale_min>$SCALE_MIN</scale_min>
21#    <scale_max>$SCALE_MAX</scale_max>
22#    <title lang="$LANG">$TITLE</title>
23#    <description lang="$LANG">$DESCRIPTION</description>
24#    <geoinfo>
25#      <poi_type_id>$POI_TYPE_ID</poi_type_1id>
26#      <name>$NAME</name>
27#    </geoinfo>
28#  </rule>
29#
30#####################################################################
31
32#use diagnostics;
33use strict;
34use warnings;
35
36use utf8;
37use IO::File;
38use File::Find;
39use File::Copy;
40use XML::Twig;
41use Getopt::Std;
42use Pod::Usage;
43use Image::Magick;
44use File::Slurp;
45use File::Basename;
46use File::Path;
47use Data::Dumper;
48
49our ($opt_v, $opt_f, $opt_h, $opt_i, $opt_n, $opt_r,$opt_s) = 0;
50getopts('hvinrsf:') or $opt_h = 1;
51pod2usage( -exitval => '1', 
52           -verbose => '1') if $opt_h;
53
54my $file_xml = './icons.xml';
55my %ICONS = ('','');
56my $i = 0;
57my $poi_reserved = 30;
58my $poi_type_id_base = $poi_reserved;
59my $default_scale_min = 1;
60my $default_scale_max = 50000;
61my $default_title_en = '';
62my $default_desc_en = '';
63my $VERBOSE = $opt_v;
64
65my @ALL_TYPES = qw(square.big square.small classic.big classic.small svg japan );
66
67my $SVN_STATUS={};
68my $SVN_VERSION = '';
69
70#####################################################################
71#
72#  M A I N
73#
74#
75chdir('./map-icons');
76unless (-e $file_xml)
77{
78  create_xml(); # Create a new XML-File if none exists
79}
80get_svn_status();
81get_icons();             # read available icons from dirs
82update_xml();            # parse and update contents  of XML-File
83chdir('..');
84exit (0);
85
86
87#####################################################################
88#
89# Get the "svn status" for all icons Files
90#
91sub get_svn_status {
92    return unless $opt_s;
93    $SVN_VERSION = `svnversion`;
94    chomp($SVN_VERSION);
95    $SVN_VERSION =~ s/M//;
96    my $svn_status = `svn -v status .`;
97    for my $line (split(/[\r\n]+/,$svn_status)) {
98        chomp $line;
99        my ($status,$rev,$rev_ci,$user,$file) = (split(/\s+/,$line),('')x5);
100        if ( $status eq "?" ) {
101            $file = $rev; 
102            $rev ='';
103        }
104        $SVN_STATUS->{$file}="$status,$rev,$rev_ci,$user";
105    }
106}
107
108
109#####################################################################
110#
111#  Parse available XML-File aund update with contents from icons dirs
112#
113#
114sub update_xml
115{
116  print STDOUT "\n----- Parsing and updating '$file_xml' -----\n";
117 
118  # Parse XML-File and look for already existing POI-Type entries
119  #
120  my $twig= new XML::Twig
121    (
122      pretty_print => 'indented',
123      empty_tags => 'normal',
124      comments => 'keep',
125      TwigHandlers => { 
126          geoinfo => \&sub_geoinfo # also deletes the entry from %ICONS
127     }
128    );
129  $twig->parsefile( "$file_xml");       # build the twig
130  my $rules= $twig->root;       # get the root of the twig (rules)
131
132  # Insert new POI-Type entries from hash of available icons
133  #
134  $i = 0;
135  my @tmp_icons = sort(keys(%ICONS));
136 
137  for my $icon (@tmp_icons)
138  {
139     insert_poi_type($icon,\$rules);
140     $i++;
141  }
142  print STDOUT "  New POI-Types added:\t$i\n";
143
144  # Print Status for poi_type_ids
145  #
146  my @rule= $rules->children;   # get the updated rule list
147
148  my @a_id;
149  $i = 0;
150  my $id_max = 0;
151  foreach my $entry (@rule)
152  {
153    if  (my $id =
154         $entry->first_child('geoinfo')->first_child('poi_type_id')->text)
155    {
156      $i++;
157      $a_id[$i] = $id; # XXX besser mit push(@a_id,$id)? denn a_id[0] wird nie belegt?
158      $id_max = $id if $id >$id_max;
159    }
160  }
161  my %unused = ('','');
162  for ( my $k = 1; $k<$id_max; $k++ ) { $unused{$k}=$k; } 
163  print STDOUT "  POI-Types defined:\t$i\n";
164  print STDOUT "  Max. poi_type_id:\t$id_max\n";
165  print STDOUT "  Unused IDs:\n  \t";
166  foreach (@a_id)
167  { 
168    if (defined($_) && exists $unused{$_}) { delete $unused{$_}; }
169  }
170  foreach (sort(keys(%unused)))
171    { print STDOUT "$_  " if ($_ > $poi_reserved) }
172  print STDOUT "\n\n";
173
174  # Write XML-File containing modified contents
175  #
176  open TMPFILE,">:utf8","./icons.tmp";
177    select TMPFILE;
178    print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
179    print "<rules>\n";
180   
181    my $j=1;
182
183
184sub entry_name($){
185    my $entry = shift;
186    return $entry->first_child('geoinfo')->first_child('name')->text();
187}
188
189    foreach my $entry (sort {entry_name($a) cmp entry_name($b) } @rule)
190     {
191       my $name = $entry->first_child('geoinfo')->first_child('name')->text();
192       next if not($opt_i) && $name =~ m/^incomming/;
193
194       $entry->print;
195       print "\n"; 
196     }
197    print "</rules>\n";
198  close TMPFILE;
199
200  # Create backup copy of old XML-File
201  #
202  move("$file_xml","$file_xml.bak") or die (" Couldn't create backup file!");
203  move("./icons.tmp","$file_xml") or die (" Couldn't remove temp file!");
204  print STDOUT " XML-File successfully updated!\n";
205
206  $twig->purge;
207
208  return;
209
210  # look, if POI-Type already exists in the file by checking for a
211  # known name inside the geoinfo tag. If true, kick it from the icons
212  # hash, because it's not needed anymore.
213  sub sub_geoinfo
214   {
215     my( $twig, $geoinfo)= @_;
216     my $poi_type_id = $geoinfo->first_child('poi_type_id')->text;
217     my $name = $geoinfo->first_child('name')->text;
218
219     if (exists $ICONS{$name}) 
220     {
221       print STDOUT "  o  $poi_type_id\t\t$name\n" if $VERBOSE;
222       $poi_type_id_base = $poi_type_id 
223           if ($poi_type_id > $poi_type_id_base);
224       delete $ICONS{"$name"};
225     }
226   }
227}
228
229
230#####################################################################
231#
232#  Insert new POI-Type into the file
233#
234#
235sub insert_poi_type
236{
237  my $name = shift(@_);
238  my $twig_root = shift(@_);
239
240  my $new_rule = new XML::Twig::Elt( 'rule');
241  $poi_type_id_base++;
242 
243  my $new_condition = new XML::Twig::Elt('condition');
244  $new_condition->set_att(k=>'poi');
245  $new_condition->set_att(v=>"$name");
246  my $new_title_en = new XML::Twig::Elt('title',$default_title_en);
247  $new_title_en->set_att(lang=>'en');
248  my $new_desc_en = new XML::Twig::Elt('description',$default_desc_en);
249  $new_desc_en->set_att(lang=>'en');
250  my $new_scale_min = new XML::Twig::Elt('scale_min',$default_scale_min);
251  my $new_scale_max = new XML::Twig::Elt('scale_max',$default_scale_max);
252  my $new_poi_type_id = new XML::Twig::Elt('poi_type_id',$poi_type_id_base);
253  my $new_name = new XML::Twig::Elt('name',$name);
254
255  $new_poi_type_id->paste('last_child',$new_rule);
256  $new_name->paste('last_child',$new_rule);
257  $new_rule->insert('geoinfo');
258  $new_desc_en->paste('first_child',$new_rule);
259  $new_title_en->paste('first_child',$new_rule);
260  $new_scale_max->paste('first_child',$new_rule);
261  $new_scale_min->paste('first_child',$new_rule);
262  $new_condition->paste('first_child',$new_rule);
263
264  $new_rule->paste('last_child',$$twig_root); 
265
266  print STDOUT "  +  $poi_type_id_base\t\t$name\n" if $VERBOSE;
267}
268
269
270#####################################################################
271#
272#  Get all the available icons in data/icons
273#
274#
275sub get_icons
276{
277  print STDOUT "\n----- Looking for available icons -----\n";
278  $i = 0;
279  find( \&format_icons,  @ALL_TYPES );
280  sub format_icons()
281  { 
282      my $icon_file = $File::Find::name;
283      if ( $icon_file =~ m/\.svn/ ) {
284      } elsif ( not($opt_i) && $icon_file =~ m/incomming/ ) {
285          print STDOUT "ignore incomming: $icon_file\n" if $VERBOSE;
286      } elsif ( $icon_file =~ m/\.(png|svg)$/ && $icon_file !~ m/empty\.(png|svg)$/ ) {
287          $i++;
288          print STDOUT "  Found icon:\t$i\t$icon_file\n" if $VERBOSE;
289          for my $type ( @ALL_TYPES ) {
290              $icon_file =~ s,^$type/,,g;
291          }
292          $icon_file =~ s,\.(png|svg)$,,g;
293          $icon_file =~ s,/,.,g;
294          $ICONS{"$icon_file"} = '1';
295      }
296  }
297  delete $ICONS{''} if (exists $ICONS{''});
298  print STDOUT " $i icons for ".keys(%ICONS)." POI-Types found in data/map-icons\n";
299 
300}
301
302#####################################################################
303#
304#  Create a new XML File and fill it with the basic POI-Types
305#
306#
307sub create_xml
308 { 
309   print STDOUT "\n----- Creating new basic XML-File \"$file_xml\" -----\n";
310   print STDOUT "\n  ATTENTION: It is possible, that the IDs will change,\n";
311   print STDOUT "\n  so it would be better, if you update an existing icons.xml!\n";
312   my @poi_types = (
313
314     { name => 'unknown',
315       poi_type_id => '1',
316       scale_min => '1',
317       scale_max => '50000',
318       description_en => 'Unassigned POI',
319       description_de => 'Nicht zugewiesener POI',
320       title_en => 'Unknown',
321       title_de => 'Unbekannt',
322     },
323     { name => 'accommodation',
324       poi_type_id => '2',
325       scale_min => '1',
326       scale_max => '50000',
327       description_en => 'Places to stay',
328       description_de => 'Hotels, Jugendherbergen, Campingpl&#228;tze',
329       title_en => 'Accommodation',
330       title_de => 'Unterkunft',
331     },
332     { name => 'education',
333       poi_type_id => '3',
334       scale_min => '1',
335       scale_max => '25000',
336       description_en => 'Schools and other educational facilities',
337       description_de => 'Schulen und andere Bildungseinrichtungen',
338       title_en => 'Education',
339       title_de => 'Bildung',
340     },
341     { name => 'food',
342       poi_type_id => '4',
343       scale_min => '1',
344       scale_max => '25000',
345       description_en => 'Restaurants, Bars, and so on...',
346       description_de => 'Restaurants, Bars, usw.',
347       title_en => 'Food',
348       title_de => 'Speiselokal',
349     },
350     { name => 'geocache',
351       poi_type_id => '5',
352       scale_min => '1',
353       scale_max => '50000',
354       description_en => 'Geocaches',
355       description_de => 'Geocaches',
356       title_en => 'Geocache',
357       title_de => 'Geocache',
358     },
359     { name => 'health',
360       poi_type_id => '6',
361       scale_min => '1',
362       scale_max => '25000',
363       description_en => 'Hospital, Doctor, Pharmacy, etc.',
364       description_de => 'Krankenh&#228;user, &#196;rzte, Apotheken',
365       title_en => 'Health',
366       title_de => 'Gesundheit',
367     },
368     { name => 'money',
369       poi_type_id => '7',
370       scale_min => '1',
371       scale_max => '25000',
372       description_en => 'Bank, ATMs, and other money-related places',
373       description_de => 'Banken, Geldautomaten, und &#228;hnliches',
374       title_en => 'Money',
375       title_de => 'Geld',
376     },
377     { name => 'nautical',
378       poi_type_id => '8',
379       scale_min => '1',
380       scale_max => '50000',
381       description_en => 'Special aeronautical Points',
382       description_de => 'Spezielle aeronautische Punkte',
383       title_en => 'aeronautical',
384       title_de => 'aeronautisch',
385     },
386     { name => 'people',
387       poi_type_id => '9',
388       scale_min => '1',
389       scale_max => '50000',
390       description_en => 'Your home, work, friends, and other people',
391       description_de => 'Dein Zuhause, die Arbeitsstelle, Freunde, und andere Personen',
392       title_en => 'People',
393       title_de => 'Person',
394     },
395     { name => 'places',
396       poi_type_id => '10',
397       scale_min => '10000',
398       scale_max => '500000',
399       description_en => 'Settlements, Mountains, and other geographical stuff',
400       description_de => 'Siedlungen, Berggipfel, und anderes geografisches Zeug',
401       title_en => 'Place',
402       title_de => 'Ort',
403     },
404     { name => 'public',
405       poi_type_id => '11',
406       scale_min => '1',
407       scale_max => '25000',
408       description_en => 'Public facilities and Administration',
409       description_de => 'Verwaltung und andere &#246;ffentliche Einrichtungen',
410
411       title_en => 'Public',
412       title_de => '&#214;ffentlich',
413     },
414     { name => 'recreation',
415       poi_type_id => '12',
416       scale_min => '1',
417       scale_max => '25000',
418       description_en => 'Places used for recreation (no sports)',
419       description_de => 'Freizeiteinrichtungen (kein Sport)',
420       title_en => 'Recreation',
421       title_de => 'Freizeit',
422     },
423     { name => 'religion',
424       poi_type_id => '13',
425       scale_min => '1',
426       scale_max => '25000',
427       description_en => 'Places and facilities related to religion',
428       description_de => 'Kirchen und andere religi&#246;se Einrichtungen',
429       title_en => 'Religion',
430       title_de => 'Religion',
431     },
432     { name => 'shopping',
433       poi_type_id => '14',
434       scale_min => '1',
435       scale_max => '25000',
436       description_en => 'All the places, where you can buy something',
437       description_de => 'Orte, an denen man etwas k&#228;uflich erwerben kann',
438       title_en => 'Shopping',
439       title_de => 'Einkaufen',
440     },
441     { name => 'sightseeing',
442       poi_type_id => '15',
443       scale_min => '1',
444       scale_max => '25000',
445       description_en => 'Historic places and other interesting buildings',
446       description_de => 'Historische Orte und andere interessante Bauwerke',
447       title_en => 'Sightseeing',
448       title_de => 'Sehensw&#252;rdigkeit',
449     },
450     { name => 'sports',
451       poi_type_id => '16',
452       scale_min => '1',
453       scale_max => '25000',
454       description_en => 'Sports clubs, stadiums, and other sports facilities',
455       description_de => 'Sportpl&#228;tze und andere sportliche Einrichtungen',
456       title_en => 'Sports',
457       title_de => 'Sport',
458     },
459     { name => 'transport',
460       poi_type_id => '17',
461       scale_min => '1',
462       scale_max => '25000',
463       description_en => 'Airports and public transportation',
464       description_de => 'Flugh&#228;fen und &#246;ffentliche Transportmittel',
465       title_en => 'Public Transport',
466       title_de => '&#214;ffentliches Transportmittel',
467     },
468     { name => 'vehicle',
469       poi_type_id => '18',
470       scale_min => '1',
471       scale_max => '25000',
472       description_en => 'Facilites for drivers, like gas stations or parking places',
473       description_de => 'Dinge f&#252;r Selbstfahrer, z.B. Tankstellen oder Parkpl&#228;tze',
474       title_en => 'Vehicle',
475       title_de => 'Fahrzeug',
476     },
477     { name => 'wlan',
478       poi_type_id => '19',
479       scale_min => '1',
480       scale_max => '25000',
481       description_en => 'WiFi-related points (Kismet)',
482       description_de => 'Accesspoints und andere WLAN-Einrichtungen (Kismet)',
483       title_en => 'WLAN',
484       title_de => 'WLAN',
485     },
486     { name => 'misc',
487       poi_type_id => '20',
488       scale_min => '1',
489       scale_max => '25000',
490       description_en => 'POIs not suitable for another category, and custom types',
491       description_de => 'Eigenkreationen, und Punkte, die in keine der anderen Kategorien passen',
492       title_en => 'Miscellaneous',
493       title_de => 'Verschiedenes',
494     },
495     { name => 'waypoint',
496       poi_type_id => '21',
497       scale_min => '1',
498       scale_max => '50000',
499       description_en => 'Waypoints, for example  to temporarily mark several places',
500       description_de => 'Wegpunkte, um z.B. temporäre Punkte zu markieren',
501       title_en => 'Waypoint',
502       title_de => 'Wegpunkt',
503     },
504   
505   );
506
507   open NEWFILE,">:utf8","./$file_xml";
508   select NEWFILE;
509
510   print"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
511   print"<rules>\n\n";
512   foreach (@poi_types)
513     {
514       print"  <rule>\n";
515       print"    <condition k=\"poi\" v=\"$$_{'name'}\" />\n";
516       print"    <scale_min>$$_{'scale_min'}</scale_min>\n";
517       print"    <scale_max>$$_{'scale_max'}</scale_max>\n";
518       print"    <title lang=\"de\">$$_{'title_de'}</title>\n";
519       print"    <title lang=\"en\">$$_{'title_en'}</title>\n";
520       print"    <description lang=\"de\">$$_{'description_de'}</description>\n";
521       print"    <description lang=\"en\">$$_{'description_en'}</description>\n";
522       print"    <geoinfo>\n";
523       print"      <poi_type_id>$$_{'poi_type_id'}</poi_type_id>\n";
524       print"      <name>$$_{'name'}</name>\n";
525       print"    </geoinfo>\n";
526       print"  </rule>\n\n";
527       print STDOUT "  +  $$_{'poi_type_id'}\t\t$$_{'name'}\n" if $VERBOSE;
528     }
529   print "</rules>\n";
530 
531   close NEWFILE;
532
533   if (-e $file_xml)
534     { print STDOUT " New XML-File \"$file_xml\" successfully created!\n"; }
535   else
536     { die " ERROR: Failed in creating new XML-File \"$file_xml\" !\n"; }
537
538 }
539
540
541__END__
542
543
544=head1 SYNOPSIS
545 
546update_icons.pl [-h] [-v] [-i] [-r] [-f XML-FILE]
547 
548=head1 OPTIONS
549 
550=over 2
551 
552=item B<--h>
553
554 Show this help
555
556=item B<-f> XML-FILE
557
558 Set file, that holds all the necessary icon and poi_type information.
559 The default file is 'icons.xml'.
560
561=item B<-v>
562
563 Enable verbose output
564
565=item B<-i>
566
567 Include incomming directory in icons.xml and overview.html
568
569=item B<-r>
570
571 Include restricted icons in overview.html
572
573=item B<-s>
574
575 add svn status to overview
576    grey is missing in svn
577    green is modified
578    red is any other condition
579 this also shows the old and new icon if it is found in the
580 .svn/ directory
581
582=item B<-n>
583    show the svn revision numbers and user too
584    needs option -s to work
585
586=back
Note: See TracBrowser for help on using the repository browser.