source: subversion/utils/rendercontrol/rendercontrol.pl @ 1414

Last change on this file since 1414 was 1414, checked in by ojw, 13 years ago

Just testing svn on this machine...

  • Property svn:executable set to *
File size: 18.0 KB
Line 
1#!/usr/bin/perl -w
2=head1 NAME
3
4rendercontrol.pl - Perl/TK GUI interface to OpenStreetMap renderers
5
6=head1 SYNOPSIS
7
8Just run the program.  It will create a Files/ directory, download some
9osmarender stuff from the web, and a list of interesting places, and popup
10a window.
11
12=head1 AUTHOR
13
14Oliver White (oliver.white@blibbleblobble.co.uk)
15
16=head1 COPYRIGHT
17
18Copyright 2006, Oliver White
19
20This program is free software; you can redistribute it and/or
21modify it under the terms of the GNU General Public License
22as published by the Free Software Foundation; either version 2
23of the License, or (at your option) any later version.
24
25This program is distributed in the hope that it will be useful,
26but WITHOUT ANY WARRANTY; without even the implied warranty of
27MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28GNU General Public License for more details.
29
30You should have received a copy of the GNU General Public License
31along with this program; if not, write to the Free Software
32Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
33
34=cut
35use strict;
36use Tk;
37use IO::Socket::INET;
38use Tk::Pane;
39use Tk::Label;
40use Tk::Menu;
41use Tk::Image;
42use Data::Dumper;
43use LWP::Simple qw(getstore);
44use File::Copy qw(copy);
45#DownloadFiles();exit;
46#-----------------------------------------------------------------------------
47# Options
48#-----------------------------------------------------------------------------
49my $NAME = "RenderControl";
50my $Files = "Files"; # Main directory
51
52#-----------------------------------------------------------------------------
53# Pre-GUI stage
54#-----------------------------------------------------------------------------
55
56# Globals
57my $Status = "Statusbar";
58my ($Lat1,$Long1,$Lat2,$Long2,$Title,$CoordsValid,$DisplayText,$ProjectName);
59my %Options = ("RenderWidth"=>"1000");
60
61# If this is the first time the program has run, ask user some questions
62FirstTime() if(! -d $Files);
63
64# Load options from a file
65LoadOptions("$Files/options.txt");
66
67#-----------------------------------------------------------------------------
68# Create GUI
69#-----------------------------------------------------------------------------
70PrintBig("Loading GUI");
71my $Window = new MainWindow(-title => $NAME);
72my %Controls;
73
74$Window->optionAdd("*tearOff", "false");
75$Window->optionAdd('*BorderWidth' => 1);
76         
77#-----------------------------------------------------------------------------
78# Create menus
79#-----------------------------------------------------------------------------
80# File menu
81my $Menu = $Window->Menu;
82my $FileMenu = $Menu->cascade(-label => "~File");
83  my $Bookmarks1 = $FileMenu->cascade(-label=> "Global bookmarks");
84  BookmarkMenu($Bookmarks1, "$Files/Bookmarks");
85  my $Bookmarks2 = $FileMenu->cascade(-label=> "JOSM Bookmarks");
86  BookmarkMenu($Bookmarks2, $Options{"JosmBookmarks"});
87 
88  my $ProjectMenu = $FileMenu->cascade(-label=> "Load");
89  ListProjects();
90 
91  $FileMenu->command(-label=> "~Save project as", -command => \&SaveProjectDialog);
92  $FileMenu->command(-label=> "E~xit", -command => sub{exit});
93
94# View menu
95my $ViewMenu = $Menu->cascade(-label => "~View");
96  $ViewMenu->command(-label=> "OSM data", -command => sub{SetView("text", "$Files/data.osm");});
97  $ViewMenu->command(-label=> "Osmarender", -command => sub{SetView("text", "$Files/osm-map-features.xml");});
98  $ViewMenu->command(-label=> "SVG", -command => sub{SetView("text", "$Files/output.svg");});
99  $ViewMenu->command(-label=> "Image", -command => sub{SetView("image", "$Files/output.gif");});
100
101  $ViewMenu->separator();
102  $ViewMenu->command(-label=> "Open SVG", -command => sub{OpenFile("Editor", "$Files/output.svg");});
103  $ViewMenu->command(-label=> "Open image", -command => sub{OpenFile("ImageEditor", "$Files/output.png");});
104
105# Update from web
106my $UpdateMenu = $Menu->cascade(-label=>"~Update");
107  $UpdateMenu->command(-label=>"~Download latest files", 
108    -command => \&DownloadFiles);
109  $UpdateMenu->command(-label=>"~Reload options", 
110    -command => sub{LoadOptions("$Files/options.txt");});
111  $UpdateMenu->command(-label=>"Reload project list",
112    -command => \&RefreshListProjects);
113# Help menu
114my $HelpMenu = $Menu->cascade(-label => "~Help");
115  $HelpMenu->command(-label=>"~Web page", 
116    -command => sub{BrowseTo("http://www.openstreetmap.org/");});
117
118$Window->configure(-menu => $Menu);
119
120#-----------------------------------------------------------------------------
121# Create rest of window
122#-----------------------------------------------------------------------------
123my $LeftFrame = $Window->Frame()->pack(-expand=>0,-fill=>'y',-side=>"left");
124my $ControlFrame = $LeftFrame->Frame(-borderwidth=>2,-relief=>'ridge')->pack(-side=>'top');
125my $ListFrame = $LeftFrame->Scrolled('Pane', -scrollbars => 'e',-borderwidth=>2,-relief=>'ridge')->pack(-side=>'bottom', -expand=>1,-fill=>'both');
126
127$ControlFrame->Entry(-textvariable=>\$Lat1)->pack(-side=>'top');
128$ControlFrame->Entry(-textvariable=>\$Lat2)->pack(-side=>'top');
129$ControlFrame->Entry(-textvariable=>\$Long1)->pack(-side=>'top');
130$ControlFrame->Entry(-textvariable=>\$Long2)->pack(-side=>'top');
131$ControlFrame->Button(-text=>"Download", -command=>\&DownloadData)->pack(-side=>'top');
132
133$ControlFrame->Entry()->pack(-side=>'top');
134$ControlFrame->Button(-text => 'Render', -command => \&Render)->pack(-side=>'left');
135$ControlFrame->Message(-textvariable => \$Status)->pack(-side=>'left', -expand=>1, -fill=>'x');
136
137my $RightFrame = $Window->Frame(-borderwidth=>2,-relief=>'ridge')->pack(-expand=>1,-fill=>'both',-side=>"right");
138my $List2 = $RightFrame->Scrolled('Pane', -scrollbars => 'se',-relief=>'ridge')->pack(-expand=>1,-fill=>'both');
139
140# Create image
141my $Image = $Window->Photo(-format=>"GIF");
142my $Canvas = $List2->Canvas(-width => $Image->width,
143        -height => $Image->height)->pack(-expand=>1, -fill=>'both');
144my $TextView = $List2->Text()->pack(-expand=>1, -fill=>'both');
145
146my $IID = $Canvas->createImage(0, 0,
147        -anchor => 'nw',
148        -image  => $Image);
149   
150AddDemoControls($ListFrame) if(0);
151MainLoop;
152
153#-----------------------------------------------------------------------------
154# Refresh the list of projects in the file menu
155#-----------------------------------------------------------------------------
156sub RefreshListProjects(){
157  $ProjectMenu->cget(-menu)->delete(0, "end");
158  ListProjects();
159}
160sub ListProjects(){
161  opendir(DIR, $Files) || return;
162  while(my $File = readdir(DIR)){
163    my $FullFile = "$Files/$File";
164    if(-d $FullFile && $File ne "." && $File ne ".."){
165      $ProjectMenu->command(
166          -label => "Proj " . $File, 
167          -command => sub{$ProjectName = $File; WithProject("load");});
168    }
169  }
170  closedir(DIR);
171}
172
173#-----------------------------------------------------------------------------
174# Dialog box allowing project files to be saved in particular place
175#-----------------------------------------------------------------------------
176sub SaveProjectDialog(){
177  my $SaveProject;
178  my $Dialog = $Window->Toplevel(-title=>"Save project");
179  $Dialog->Message(-text=>"Enter a project name")->pack();
180  $Dialog->Entry(-textvariable=>\$SaveProject)->pack();
181  $Dialog->Button(-text=>"Cancel", -command=>sub{$Dialog->withdraw()})->pack(-side=>'left');
182  $Dialog->Button(-text=>"OK", -command=>sub{$ProjectName = $SaveProject; WithProject("save"); $Dialog->withdraw()})->pack(-side=>'right');
183}
184
185#-----------------------------------------------------------------------------
186# Do something with a "project" (group of data files)
187# - load (from project directory into Files/ directory)
188# - save (into project directory)
189# - delete project directory
190#-----------------------------------------------------------------------------
191sub WithProject(){
192  my $Mode = shift();
193  return if(!$ProjectName);
194 
195  my $ProjectDir = "$Files/$ProjectName";
196  mkdir($ProjectDir) if(! -d $ProjectDir && $Mode eq "save");
197 
198  foreach ("data.osm","output.svg","output.png","output.jpg","output.gif"){
199    if($Mode eq "save"){
200      copy("$Files/$_","$ProjectDir/$_");
201    }
202    elsif($Mode eq "load"){
203      copy("$ProjectDir/$_", "$Files/$_");
204    }
205    elsif($Mode eq "delete"){
206      unlink "$ProjectDir/$_";
207    }
208  }
209  unlink $ProjectDir if($Mode eq "delete");
210}
211
212#-----------------------------------------------------------------------------
213# Download all rendering files from disk
214#-----------------------------------------------------------------------------
215sub DownloadFiles(){
216  my @Files = ("http://svn.openstreetmap.org/utils/osmarender/osmarender.xsl", 
217  "http://svn.openstreetmap.org/utils/osmarender/osm-map-features.xml",
218  "http://wiki.openstreetmap.org/index.php/OJW/Bookmarks",
219  "http://svn.openstreetmap.org/freemap/freemap.xml");
220
221  foreach my $File(@Files){
222    if($File =~ /\/([^\\\/]*?)$/){
223      my $Title = $1;
224      $Status = "Downloading $Title";
225      my $Store = "$Files/$Title";
226      print "Downloading $File to $Store\n";
227      getstore($File, $Store);
228    }
229  }
230  $Status = "Download complete";
231}
232
233#-----------------------------------------------------------------------------
234# Downloads OSM data from web
235#-----------------------------------------------------------------------------
236sub DownloadData(){
237  if(!$CoordsValid){
238    $Status = "Enter some coordinates, or load a bookmark";
239    return;
240    }
241
242  PrintBig("Downloading $Title ($Lat1,$Long1,$Lat2,$Long2)");
243   
244  $Options{"username"} =~ s/\@/%40/;
245 
246  my $URL = sprintf( "http://%s:%s\@www.openstreetmap.org/api/0.3/map?bbox=$Long1,$Lat1,$Long2,$Lat2",
247  $Options{"username"},
248  $Options{"password"});
249 
250  $Status = "Downloading\n";
251  getstore($URL, "$Files/data.osm");
252  $Status = "Download complete\n";
253}
254
255#-----------------------------------------------------------------------------
256# Renders a map
257#-----------------------------------------------------------------------------
258sub Render(){
259  if($Options{"XmlStarlet"}){
260    my $Cmd = sprintf("\"%s\" tr %s %s > %s",
261      $Options{"XmlStarlet"},
262      "$Files/osmarender.xsl",
263      "$Files/osm-map-features.xml",
264      "$Files/output.svg");
265    `$Cmd`;
266    $Status = "Render complete";
267  }
268  else {
269    $Status = "No XLST program (e.g. xmlstarlet) available";
270    return;
271  }
272 
273  if($Options{"Inkscape"}){
274    my $Cmd = sprintf("\"%s\" -D -w %d -b FFFFFF -e %s %s",
275      $Options{"Inkscape"},
276      $Options{"RenderWidth"},
277      "$Files/output.png",
278      "$Files/output.svg");
279   
280    PrintBig($Cmd); 
281    `$Cmd`;
282  }
283  else{
284    $Status = "No SVG renderer available";
285    return;
286  }
287  ConvertOutputs();
288}
289#-----------------------------------------------------------------------------
290# Convert between bitmap graphics formats
291#-----------------------------------------------------------------------------
292sub ConvertOutputs(){
293  return if(!$Options{"ImageMagick"});
294 
295  foreach my $Output("$Files/output.png","$Files/output.gif"){
296    my $Cmd = sprintf("\"%s\" %s %s",
297      $Options{"ImageMagick"},
298      "$Files/output.png",
299      $Output);
300   
301    `$Cmd`;
302  }
303 
304  SetView("image","$Files/output.gif");
305}
306
307#-----------------------------------------------------------------------------
308# Set what's displayed in the right-hand pane
309#-----------------------------------------------------------------------------
310sub SetView(){
311  my ($Style, $Filename) = @_;
312  if($Style eq "text"){
313    print "Loading text file $Filename\n";
314
315    if(open(IN, "<",$Filename)){
316      $DisplayText = join('', <IN>);
317      close IN;
318    }
319    else{
320      $DisplayText = "File not available:\n$Filename\n";
321    }
322
323    $TextView->delete('1.0','end');
324    $TextView->insert("end", $DisplayText);
325
326    $Canvas->pack('forget');
327    $TextView->pack();
328  }
329  elsif($Style eq "image"){
330    print "Loading image $Filename\n";
331    $Canvas->pack();
332   
333    $Image->configure(-file=>$Filename);
334
335    $Canvas->configure(-width => $Image->width);
336    $Canvas->configure(-height => $Image->height);
337   
338    $TextView->pack('forget');
339  }
340  else{
341    print STDERR "Unknown type of object to display";
342  }
343}
344
345#-----------------------------------------------------------------------------
346# Open a file using external editor
347#  * param1 is what program to use, and is a reference to something in %Options
348#  * param2 is the filename to open
349#-----------------------------------------------------------------------------
350sub OpenFile("ImageEditor", "$Files/output.png"){
351  my ($ProgramType, $Filename) = @_;
352  my $Program = $Options{$ProgramType};
353  if(!$Program){
354    print STDERR "Can't find a $ProgramType to open $Filename\n";
355    return;
356  }
357  my $Cmd = sprintf("\"%s\" \"%s\"", $Program, $Filename);
358  PrintBig($Cmd);
359  `$Cmd`;
360}
361
362#-----------------------------------------------------------------------------
363# Create a submenu showing all bookmarks loaded from a file, where clicking on
364# any menu loads its coordinates into appropriate places
365#-----------------------------------------------------------------------------
366sub BookmarkMenu(){
367  my ($Menu, $File) = @_;
368  return if(!$File);
369 
370  open(IN, $File) || return;
371  my $Data = join('', <IN>);
372  close IN;
373  $Data = $1 if($Data =~ /START_DATA(.*)END_DATA/ms);
374
375  foreach my $Line(split(/\n/, $Data)){
376    my ($Name, $Lat1, $Long1, $Lat2, $Long2, $Spare) = split(/,/,$Line);
377    $Menu->command(-label=> $Name, -command => sub{SetData($Name,$Lat1, $Long1, $Lat2, $Long2);}) if($Name && $Spare eq "false");
378  }
379
380  $Menu->separator();
381  $Menu->command(-label=> "Edit this list (web link)", 
382    -command => sub{BrowseTo("http://wiki.openstreetmap.org/index.php/OJW/Bookmarks")});
383}
384
385#-----------------------------------------------------------------------------
386# Opens a web browser to display the specified URL
387#-----------------------------------------------------------------------------
388sub BrowseTo(){
389  my $URL = shift();
390  my $Browser = $Options{"Browser"};
391  `\"$Browser\" $URL` if($Browser);
392}
393
394#-----------------------------------------------------------------------------
395# Sets-up the application, first time it's run
396#-----------------------------------------------------------------------------
397sub FirstTime(){
398  print "Welcome to $NAME\n\nThis looks like the first time you've run this program.\nIs it okay to create a directory in $Files, and download some data from the web? (y/n)\n";
399  exit if(<> =~ /N/i);
400  mkdir($Files);
401   
402 
403  # Get username and password
404  print "\n\nYou now have the opportunity to enter an OSM username and password.\n\nThese will appear on your screen, so check nobody is watching!\nThese will be stored in plaintext on disk\n\nIf you don't want to enter a password yet, just press enter twice,\nthen edit $Files/options.txt later\n";
405  print "Username:"; $Options{"username"} = <>;
406  print "Password:"; $Options{"password"} = <>;
407  chomp($Options{"username"}, $Options{"password"});
408  print "\n";
409 
410  LookFor("Browser", 
411    "C:\\Program Files\\Mozilla Firefox\\firefox.exe", 
412    "C:\\windows\\iexplore.exe", 
413    "C:\\winnt\\iexplore.exe", 
414    "C:\\windows\\iexplore.exe", 
415        "C:/Program Files/Internet Explorer/iexplore.exe",
416    "/usr/bin/firefox");
417 
418  LookFor("XmlStarlet", 
419    "C:\\xml\\xml.exe", 
420    "/usr/bin/xmlstarlet");
421 
422  LookFor("Inkscape", 
423    "C:\\Program Files\\inkscape\\inkscape.exe", 
424    "/usr/bin/inkscape");
425   
426  LookFor("ImageMagick", 
427    "/usr/bin/convert");
428 
429  LookFor("JosmBookmarks", 
430    "~/.josm/Bookmarks",
431        "C:/Documents and Settings/oliverwhite.CUESIM/.josm/bookmarks");
432
433  LookFor("JOSM", 
434    "C:/home/osm/josm-latest.jar");
435 
436  LookFor("Editor", 
437    "c:/windows/notepad.exe",
438    "c:/winnt/notepad.exe",
439        "/usr/bin/kate",
440        "/usr/bin/emacs");
441       
442  LookFor("ImageEditor", 
443    "C:/Program Files/GIMP-2.0/bin/gimp-win-remote.exe",
444        "/usr/bin/gimp",
445        "/usr/bin/gqview");
446
447  SaveOptions("$Files/options.txt");
448 
449  # Download files for the first time
450  PrintBig("Downloading latest osmarender");
451  DownloadFiles(); 
452 
453}
454
455#-----------------------------------------------------------------------------
456# Save all options to disk
457#-----------------------------------------------------------------------------
458sub SaveOptions(){
459  my $Filename = shift();
460  if(open(SAVEOPTIONS, ">", $Filename)){
461    foreach my $Option(keys %Options){
462      printf SAVEOPTIONS "%s=%s\n", $Option, $Options{$Option};
463    }
464    close SAVEOPTIONS;
465  }
466  else{
467    print STDERR "Problem: Couldn't save options to $Filename\n";
468  }
469}
470
471#-----------------------------------------------------------------------------
472# Try to find a particular program
473# Usage: LookFor("SettingName", "PossibleLocation1", "PossibleLocation2",...)
474#-----------------------------------------------------------------------------
475sub LookFor(){
476  my ($Name, @Options) = @_;
477  foreach my $Option(@Options){
478    if(-f $Option){
479      $Options{$Name} = $Option;
480      print "Using $Name: $Option\n";
481      return;
482    }
483  }
484  print "Where can I find $Name on this computer? (press Enter if you don't know)\n";
485  $Options{$Name} = <>;
486  chomp($Options{$Name});
487}
488
489#-----------------------------------------------------------------------------
490# Load all options from disk
491# as name=value pairs (one per line)
492#-----------------------------------------------------------------------------
493sub LoadOptions(){
494  my $Filename = shift();
495  open(OPT, "<", $Filename) || return;
496  while(my $Line = <OPT>){
497    chomp $Line;
498    if($Line =~ /^\s*(\w+)\s*=\s*(.*)/){
499      $Options{$1} = $2;
500    }
501  }
502  close OPT;
503}
504
505#-----------------------------------------------------------------------------
506# Temporary: fill the left column with dummy controls to see what it looks like
507#-----------------------------------------------------------------------------
508sub AddDemoControls(){
509  my($Frame) = @_;
510 
511  foreach (1..60){
512    my $ItemFrame = $Frame->Frame()->pack(-expand=>1, -fill=>'x');
513    $ItemFrame->Checkbutton(-text => "TODO $_")->pack(-side=>'top')->deselect();
514  }
515}
516
517#-----------------------------------------------------------------------------
518# Sets the download area (used when clicking on bookmark menu)
519#-----------------------------------------------------------------------------
520sub SetData(){
521  ($Title,$Lat1,$Long1,$Lat2,$Long2) = @_;
522  $CoordsValid = 1;
523}
524
525
526#-----------------------------------------------------------------------------
527# Prints a message in big letters on console
528#-----------------------------------------------------------------------------
529sub PrintBig(){
530    print STDERR "=" x 80 . "\n" . shift() . "\n" . "=" x 80 . "\n";
531}
Note: See TracBrowser for help on using the repository browser.