| 1 | #!/usr/bin/perl |
|---|
| 2 | # This file is part of the McStas neutron ray-trace simulation package |
|---|
| 3 | # Copyright (C) 1997-2004, All rights reserved |
|---|
| 4 | # Risoe National Laborartory, Roskilde, Denmark |
|---|
| 5 | # Institut Laue Langevin, Grenoble, France |
|---|
| 6 | # |
|---|
| 7 | # This program is free software; you can redistribute it and/or modify |
|---|
| 8 | # it under the terms of the GNU General Public License as published by |
|---|
| 9 | # the Free Software Foundation; version 2 of the License. |
|---|
| 10 | # |
|---|
| 11 | # This program is distributed in the hope that it will be useful, |
|---|
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | # GNU General Public License for more details. |
|---|
| 15 | # |
|---|
| 16 | # You should have received a copy of the GNU General Public License |
|---|
| 17 | # along with this program; if not, write to the Free Software |
|---|
| 18 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 19 | # |
|---|
| 20 | # mcformatgui.pl - perl-Tk gui for mcformat and mcconvert tools. |
|---|
| 21 | # |
|---|
| 22 | |
|---|
| 23 | use Cwd; |
|---|
| 24 | use IPC::Open2; |
|---|
| 25 | use File::Basename; |
|---|
| 26 | use File::Path; |
|---|
| 27 | use File::Copy; |
|---|
| 28 | use File::Spec; |
|---|
| 29 | use Time::localtime; |
|---|
| 30 | use Tk::Balloon; |
|---|
| 31 | use Config; |
|---|
| 32 | use FileHandle; |
|---|
| 33 | |
|---|
| 34 | |
|---|
| 35 | # Determine the path to the McStas system directory. This must be done |
|---|
| 36 | # in the BEGIN block so that it can be used in a "use lib" statement |
|---|
| 37 | # afterwards. |
|---|
| 38 | BEGIN { |
|---|
| 39 | # default configuration (for all high level perl scripts) |
|---|
| 40 | if($ENV{"MCSTAS"}) { |
|---|
| 41 | $MCSTAS::sys_dir = $ENV{"MCSTAS"}; |
|---|
| 42 | } else { |
|---|
| 43 | if ($Config{'osname'} eq 'MSWin32') { |
|---|
| 44 | $MCSTAS::sys_dir = "c:\\mcstas\\lib"; |
|---|
| 45 | } else { |
|---|
| 46 | $MCSTAS::sys_dir = "/usr/local/lib/mcstas"; |
|---|
| 47 | } |
|---|
| 48 | } |
|---|
| 49 | $MCSTAS::perl_dir = "$MCSTAS::sys_dir/tools/perl"; |
|---|
| 50 | |
|---|
| 51 | # custom configuration (this script) |
|---|
| 52 | $MCSTAS::perl_modules = "$MCSTAS::perl_dir/modules"; |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | use lib $MCSTAS::perl_dir; |
|---|
| 56 | use lib $MCSTAS::perl_modules; |
|---|
| 57 | require "mcstas_config.perl"; |
|---|
| 58 | |
|---|
| 59 | # Overload with user's personal config |
|---|
| 60 | if ($ENV{"HOME"} && -e $ENV{"HOME"}."/.mcstas/mcstas_config.perl") { |
|---|
| 61 | require $ENV{"HOME"}."/.mcstas/mcstas_config.perl"; |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | my $dodisplay = 0; |
|---|
| 65 | my $timeout = 5; |
|---|
| 66 | my $show_help = 0; |
|---|
| 67 | my $iformats = ['McStas','Scilab','Matlab']; |
|---|
| 68 | my $oformats; |
|---|
| 69 | my $runmodes; |
|---|
| 70 | my $iformat="McStas"; |
|---|
| 71 | my $oformat="McStas"; |
|---|
| 72 | my $runmode="Merge"; |
|---|
| 73 | my $inputdir; |
|---|
| 74 | my $outputdir; |
|---|
| 75 | my $oformats_iMcStas; |
|---|
| 76 | my $oformats_iMatlab = ['Scilab']; |
|---|
| 77 | my $oformats_iScilab = ['Matlab']; |
|---|
| 78 | my $runmodes_iMcStas = ['Convert','Merge','Scan assembly','Scan Merge']; |
|---|
| 79 | my $runmodes_ilab = ['Convert']; |
|---|
| 80 | my $recordlog=0; |
|---|
| 81 | |
|---|
| 82 | my $ext; |
|---|
| 83 | my $filename = ""; |
|---|
| 84 | my $i; |
|---|
| 85 | my $continue; |
|---|
| 86 | |
|---|
| 87 | my $iformat_crtl; |
|---|
| 88 | my $oformat_line=""; |
|---|
| 89 | |
|---|
| 90 | if ($MCSTAS::mcstas_config{'NEXUS'} ne "") { |
|---|
| 91 | $oformats_iMcStas = ['McStas','Scilab','Matlab','IDL','HTML','XML','Octave','NeXus']; |
|---|
| 92 | } else { |
|---|
| 93 | $oformats_iMcStas = ['McStas','Scilab','Matlab','IDL','HTML','XML','Octave']; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | my $cmd; |
|---|
| 97 | my $logfile; |
|---|
| 98 | my $date = time(); |
|---|
| 99 | $logfile = "mcformatgui_${date}.log"; |
|---|
| 100 | Tkgui(); |
|---|
| 101 | $iformat = iformat_select($inputdir); |
|---|
| 102 | my $fid; |
|---|
| 103 | |
|---|
| 104 | if ($recordlog) { |
|---|
| 105 | $logfile = "mcformatgui_${date}.log"; |
|---|
| 106 | $fid = new FileHandle "> $logfile"; |
|---|
| 107 | if (defined $fid) { |
|---|
| 108 | print $fid "# mcformatgui log file '$logfile'\n"; |
|---|
| 109 | print $fid "# Directories: $inputdir \@ $iformat format -> $outputdir \@ $oformat format.\n"; |
|---|
| 110 | print $fid "# Action: $runmode\n"; |
|---|
| 111 | |
|---|
| 112 | print "mcformatgui: Recording $inputdir -> $outputdir operations into log file '$logfile'\n"; |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | if ($iformat =~ /Matlab|Scilab/i && $oformat =~ /Matlab|Scilab/i |
|---|
| 117 | && $iformat ne $oformat && $runmode eq "Convert") { |
|---|
| 118 | print "Using mcconvert.pl for $iformat -> $oformat conversion...\n"; |
|---|
| 119 | $cmd="mcconvert$MCSTAS::mcstas_config{'SUFFIX'} --format=$oformat --indir=$inputdir --outdir=$outputdir"; |
|---|
| 120 | |
|---|
| 121 | } elsif ($oformat_line !~ /binary/s) { |
|---|
| 122 | print "Input format is McStas, running mcformat to $runmode data. Output will go to $outputdir in $oformat...\n"; |
|---|
| 123 | my $mode=""; |
|---|
| 124 | if ($oformat =~ /IDL/i) { $oformat="IDL_binary"; } |
|---|
| 125 | if ($runmode =~ /Scan assembly/i) { $mode="--scan-only"; } |
|---|
| 126 | elsif ($runmode =~ /Scan Merge/i) { $mode="--scan"; } |
|---|
| 127 | elsif ($runmode =~ /merge/i) { $mode="--merge"; } |
|---|
| 128 | if ($mode =~ /scan/i && $oformat !~ /McStas/i) { |
|---|
| 129 | my $ret = $w->messageBox( |
|---|
| 130 | -message => "For a Scan Operation ($mode)\n |
|---|
| 131 | The McStas/PGPLOT output format if prefered.\n |
|---|
| 132 | Other formats will not display correctly.\n |
|---|
| 133 | Press 'Yes' to export in McStas\n |
|---|
| 134 | or 'No' to keep $oformat.", |
|---|
| 135 | -title => "Scan operation: McStas prefered.", |
|---|
| 136 | -type => 'YesNo', |
|---|
| 137 | -icon => 'question', |
|---|
| 138 | -default => 'yes'); |
|---|
| 139 | if (lc($ret) eq "yes") { $oformat="McStas"; } |
|---|
| 140 | } |
|---|
| 141 | $cmd="mcformat"; |
|---|
| 142 | if ($Config{'osname'} eq 'MSWin32') { $cmd .= ".$MCSTAS::mcstas_config{'EXE'}"; } |
|---|
| 143 | $cmd.=" --format=$oformat --dir=$outputdir $inputdir $mode"; |
|---|
| 144 | } else { |
|---|
| 145 | print "mcformatgui: I do not have any appropriate method for conversion.\n"; |
|---|
| 146 | print "ERROR Try mcformat or mcconvert commands manually.\n"; |
|---|
| 147 | exit(); |
|---|
| 148 | } |
|---|
| 149 | if ($recordlog && defined $fid) { |
|---|
| 150 | print $fid "# Command: $cmd\n\n"; |
|---|
| 151 | $cmd .= ">> $logfile 2>&1 "; |
|---|
| 152 | close($fid); |
|---|
| 153 | } |
|---|
| 154 | print "Executing: $cmd\n"; |
|---|
| 155 | system("$cmd"); |
|---|
| 156 | |
|---|
| 157 | sub Tkgui { |
|---|
| 158 | use Tk; |
|---|
| 159 | use Tk::Toplevel; |
|---|
| 160 | use Tk::DirTree; |
|---|
| 161 | $continue = 0; |
|---|
| 162 | my $win = new MainWindow(-title => "McFormatGui: Handle McStas datasets"); |
|---|
| 163 | build_gui($win); |
|---|
| 164 | MainLoop; |
|---|
| 165 | if (!($continue == 1)) { |
|---|
| 166 | exit; |
|---|
| 167 | } |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | sub build_gui { |
|---|
| 171 | # When mcdaemon is run without any input parms, we'll build a gui |
|---|
| 172 | # to set the parameters. |
|---|
| 173 | my ($win) = @_; |
|---|
| 174 | my $topframe = $win->Frame(-relief => 'raised', -borderwidth => 2); |
|---|
| 175 | my $b = $win->Balloon(-state => 'balloon'); |
|---|
| 176 | $topframe->pack(-side => "top", -fill => "both", -ipady => 3, -ipadx => 3); |
|---|
| 177 | my $tmp1 = $topframe->Label(-text => "Input dir(s):", -anchor => 'w', |
|---|
| 178 | -justify => "center", -width => 15, -fg => 'blue')->pack(-side => "left"); |
|---|
| 179 | $b->attach($tmp1, -balloonmsg => "Data directory to convert"); |
|---|
| 180 | $topframe->Entry(-width => 40, -relief => "sunken", |
|---|
| 181 | -textvariable => \$inputdir)->pack(-side => "left"); |
|---|
| 182 | my $dirselect = $topframe->Button(-text => "Select", -command => sub { |
|---|
| 183 | $inputdir = select_dir($inputdir); |
|---|
| 184 | $iformat = iformat_select($inputdir); |
|---|
| 185 | })->pack(-side => "left"); |
|---|
| 186 | $b->attach($dirselect, -balloonmsg => "Select an existing directory"); |
|---|
| 187 | |
|---|
| 188 | my $top2frame = $win->Frame(-relief => 'raised', -borderwidth => 2); |
|---|
| 189 | $top2frame->pack(-side => "top", -fill => "both", -ipady => 3, -ipadx => 3); |
|---|
| 190 | $tmp2 = $top2frame->Label(-text => "Output dir :", -anchor => 'w', |
|---|
| 191 | -justify => "center", -width => 15, -fg => 'blue')->pack(-side => "left"); |
|---|
| 192 | $b->attach($tmp2, -balloonmsg => "Target directory\nfor converted data"); |
|---|
| 193 | $top2frame->Entry(-width => 40, -relief => "sunken", |
|---|
| 194 | -textvariable => \$outputdir)->pack(-side => "left"); |
|---|
| 195 | my $dirselect = $top2frame->Button(-text => "Select", -command => sub { |
|---|
| 196 | $outputdir = select_dir($outputdir); |
|---|
| 197 | $outputdir = check_dir($win,$outputdir); |
|---|
| 198 | })->pack(-side => "left"); |
|---|
| 199 | $b->attach($dirselect, -balloonmsg => "Select an existing directory\nor enter a new one"); |
|---|
| 200 | |
|---|
| 201 | my $midframe = $win->Frame(-relief => 'raised', -borderwidth => 2); |
|---|
| 202 | $midframe->pack(-side => "top", -fill => "both", -ipady => 3, -ipadx => 3); |
|---|
| 203 | $tmp3=$midframe->Label(-text => "Output format: ", -anchor => 'w', |
|---|
| 204 | -justify => "center", -fg => 'blue')->pack(-side => "left"); |
|---|
| 205 | $b->attach($tmp3, -balloonmsg => "Format for converted data\nNOTE: If input data is Matlab/Scilab\n and output format is Scilab/Matlab\n 'Convert' mode will work also with binary data."); |
|---|
| 206 | $oformats = $oformats_iMcStas; |
|---|
| 207 | $oformat_ctrl = $midframe->Optionmenu(-textvariable => \$oformat, -options => |
|---|
| 208 | $oformats)->pack(-side => 'left'); |
|---|
| 209 | $tmp4=$midframe->Label(-text => "Conversion mode: ", -anchor => 'w', |
|---|
| 210 | -justify => "center", -fg => 'blue')->pack(-side => "left"); |
|---|
| 211 | $b->attach($tmp4, -balloonmsg => "Convert: convert files one by one\nMerge: convert files and merge equivalent ones (e.g. clusters/grids)\nScan assembly: convert files and gather them in scan series\nScan merge: same as assembly, but also merge equivalent files"); |
|---|
| 212 | $runmodes = $runmodes_iMcStas; |
|---|
| 213 | $runmode_ctrl = $midframe->Optionmenu(-textvariable => \$runmode, -options => |
|---|
| 214 | $runmodes)->pack(-side => 'left'); |
|---|
| 215 | |
|---|
| 216 | my $bottomframe = $win->Frame(-relief => 'raised', -borderwidth => 2); |
|---|
| 217 | $bottomframe->pack(-side => "top", -fill => "both", -ipady => 3, -ipadx => 3); |
|---|
| 218 | my $recordlog = $bottomframe->Checkbutton(-text => "Record Log file",-variable => \$recordlog)->pack(-side => 'left'); |
|---|
| 219 | $b->attach($recordlog, -balloonmsg => "Records data handling operations into $logfile file"); |
|---|
| 220 | |
|---|
| 221 | $bottomframe->Button(-text => "Cancel", -fg => 'red', -command => sub {exit;})->pack(-side => "right", -anchor => "e"); |
|---|
| 222 | $bottomframe->Button(-text => "Ok", -fg => 'green', -command => sub { |
|---|
| 223 | if ($inputdir && $outputdir) { |
|---|
| 224 | $outputdir = check_dir($win,$outputdir); |
|---|
| 225 | $continue=1; $win->destroy; |
|---|
| 226 | } else { |
|---|
| 227 | $win->messageBox( |
|---|
| 228 | -message => "You must select both an input and an output dir!", |
|---|
| 229 | -title => "Problem:", |
|---|
| 230 | -type => 'ok', |
|---|
| 231 | -icon => 'error', |
|---|
| 232 | -default => 'ok'); |
|---|
| 233 | } |
|---|
| 234 | })->pack(-side => "right", -anchor => "w"); |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | sub check_dir { |
|---|
| 238 | my ($win, $output) = @_; |
|---|
| 239 | if (-d $output && -e $output) { |
|---|
| 240 | $output = File::Spec->catfile( $output, "$date" ); |
|---|
| 241 | $win->messageBox( |
|---|
| 242 | -message => "For safety reasons I will create the subdir \n\n$output\n\n as final destination.\n\n ". |
|---|
| 243 | "This directory does not exist now but will be created at runtime.\n", |
|---|
| 244 | -title => "Notice: Directory exists", |
|---|
| 245 | -type => 'ok', |
|---|
| 246 | -icon => 'info', |
|---|
| 247 | -default => 'ok'); |
|---|
| 248 | } |
|---|
| 249 | return $output; |
|---|
| 250 | } |
|---|
| 251 | |
|---|
| 252 | sub select_dir { |
|---|
| 253 | my ($start_dir) = @_; |
|---|
| 254 | my $top = new MainWindow; |
|---|
| 255 | $top->withdraw; |
|---|
| 256 | |
|---|
| 257 | my $t = $top->Toplevel; |
|---|
| 258 | $t->title("Choose dir to monitor:"); |
|---|
| 259 | my $ok = 0; |
|---|
| 260 | my $f = $t->Frame->pack(-fill => "x", -side => "bottom"); |
|---|
| 261 | |
|---|
| 262 | my $curr_dir; |
|---|
| 263 | |
|---|
| 264 | if ($start_dir) { |
|---|
| 265 | $curr_dir = $start_dir; |
|---|
| 266 | } else { |
|---|
| 267 | $curr_dir = getcwd(); |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | my $d; |
|---|
| 271 | $d = $t->Scrolled('DirTree', |
|---|
| 272 | -scrollbars => 'osoe', |
|---|
| 273 | -width => 35, |
|---|
| 274 | -height => 20, |
|---|
| 275 | -selectmode => 'browse', |
|---|
| 276 | -exportselection => 1, |
|---|
| 277 | -browsecmd => sub { $curr_dir = shift }, |
|---|
| 278 | -command => sub { $ok = 1 }, |
|---|
| 279 | )->pack(-fill => "both", -expand => 1); |
|---|
| 280 | $f->Button(-text => 'Ok', |
|---|
| 281 | -command => sub { $ok = 1 })->pack(-side => 'left'); |
|---|
| 282 | $f->Button(-text => 'Cancel', |
|---|
| 283 | -command => sub { $ok = -1 })->pack(-side => 'left'); |
|---|
| 284 | |
|---|
| 285 | $f->waitVariable(\$ok); |
|---|
| 286 | |
|---|
| 287 | $top->destroy; |
|---|
| 288 | |
|---|
| 289 | if ($ok == 1) { |
|---|
| 290 | return $curr_dir; |
|---|
| 291 | } else { |
|---|
| 292 | return $start_dir; |
|---|
| 293 | } |
|---|
| 294 | |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | sub iformat_select { |
|---|
| 298 | my ($dir) = @_; |
|---|
| 299 | my $file = $dir; |
|---|
| 300 | |
|---|
| 301 | # check input data directory |
|---|
| 302 | if (-d $file) { # check if dir containing result file |
|---|
| 303 | my $newfile = "$file/mcstas"; |
|---|
| 304 | if (-e "$newfile.m" || -e "$newfile.sci" || -e "$newfile.sim" || -e "$newfile.html" || -e "$newfile.nxs" || -e "$newfile.pro" || -e "$newfile.xml") { |
|---|
| 305 | $file = $newfile; } |
|---|
| 306 | } |
|---|
| 307 | |
|---|
| 308 | # look if there is only one file type and set iformat |
|---|
| 309 | if (-e "$file.m") { $iformat = "Matlab"; $file = "$file.m"; } |
|---|
| 310 | if (-e "$file.sci") { $iformat = "Scilab"; $file = "$file.sci"; } |
|---|
| 311 | if (-e "$file.sim") { $iformat = "McStas"; $file = "$file.sim"; } |
|---|
| 312 | if (-e "$file.html") { $iformat = "HTML"; $file = "$file.html"; } |
|---|
| 313 | if (-e "$file.xml") { $iformat = "XML"; $file = "$file.xml"; } |
|---|
| 314 | if (-e "$file.pro") { $iformat = "IDL"; $file = "$file.pro"; } |
|---|
| 315 | if (-e "$file.nxs") { $iformat = "NeXus"; $file = "$file.nxs"; } |
|---|
| 316 | |
|---|
| 317 | if (open $handle, $file) { |
|---|
| 318 | while(<$handle>) { |
|---|
| 319 | if(/Format\s*(.*?)\s*$/i) { |
|---|
| 320 | $oformat_line = $1; |
|---|
| 321 | } |
|---|
| 322 | } |
|---|
| 323 | close($fid); |
|---|
| 324 | print "Input directory $dir presumably contains data in $iformat format.\n"; |
|---|
| 325 | if ($oformat_line =~ /binary/i) { print " It contains binary blocks.\n"; } |
|---|
| 326 | } else { print "mcformatgui: Warning: Could not open file '$file'. Conversion may fail.\n"; } |
|---|
| 327 | |
|---|
| 328 | return($iformat); |
|---|
| 329 | } |
|---|
| 330 | |
|---|