fcm_gui 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. #!/usr/bin/env perl
  2. #-------------------------------------------------------------------------------
  3. # (C) Crown copyright Met Office. All rights reserved.
  4. # For further details please refer to the file COPYRIGHT.txt
  5. # which you should have received as part of this distribution.
  6. #-------------------------------------------------------------------------------
  7. use strict;
  8. use warnings;
  9. use FindBin;
  10. use lib "$FindBin::Bin/../lib";
  11. use Cwd;
  12. use Fcm::Config;
  13. use Fcm::Keyword;
  14. use Fcm::Timer;
  15. use Fcm::Util;
  16. use File::Basename;
  17. use File::Spec;
  18. use Tk;
  19. use Tk::ROText;
  20. # ------------------------------------------------------------------------------
  21. # Argument
  22. if (@ARGV) {
  23. my $dir = shift @ARGV;
  24. chdir $dir if -d $dir;
  25. }
  26. # Get configuration settings
  27. my $config = Fcm::Config->new ();
  28. $config->get_config ();
  29. # ------------------------------------------------------------------------------
  30. # FCM subcommands
  31. my @subcmds = qw/CHECKOUT BRANCH STATUS DIFF ADD DELETE MERGE CONFLICTS COMMIT
  32. UPDATE SWITCH/;
  33. # Subcommands allowed when CWD is not a WC
  34. my @nwc_subcmds = qw/CHECKOUT BRANCH/;
  35. # Subcommands allowed, when CWD is a WC
  36. my @wc_subcmds = qw/STATUS BRANCH DIFF ADD DELETE MERGE CONFLICTS COMMIT UPDATE
  37. SWITCH/;
  38. # Subcommands that apply to WC only
  39. my @wco_subcmds = qw/BRANCH STATUS DIFF ADD DELETE MERGE CONFLICTS COMMIT UPDATE
  40. SWITCH/;
  41. # Subcommands that apply to top level WC only
  42. my @wcto_subcmds = qw/BRANCH MERGE COMMIT UPDATE SWITCH/;
  43. # Selected subcommand
  44. my $selsubcmd = '';
  45. # Selected subcommand is running?
  46. my $cmdrunning = 0;
  47. # PID of running subcommand
  48. my $cmdpid = undef;
  49. # List of subcommand frames
  50. my %subcmd_f;
  51. # List of subcommand buttons
  52. my %subcmd_b;
  53. # List of subcommand button help strings
  54. my %subcmd_help = (
  55. BRANCH => 'list information about, create or delete a branch.',
  56. CHECKOUT => 'check out a working copy from a repository.',
  57. STATUS => 'print the status of working copy files and directories.',
  58. DIFF => 'display the differences in modified files.',
  59. ADD => 'put files and directories under version control.',
  60. DELETE => 'remove files and directories from version control.',
  61. MERGE => 'merge changes into your working copy.',
  62. CONFLICTS => 'use a graphical tool to resolve conflicts in your working copy.',
  63. COMMIT => 'send changes from your working copy to the repository.',
  64. UPDATE => 'bring changes from the repository into your working copy.',
  65. SWITCH => 'update your working copy to a different URL.',
  66. );
  67. for (keys %subcmd_help) {
  68. $subcmd_help{$_} = 'Select the "' . lc ($_) . '" sub-command - ' .
  69. $subcmd_help{$_};
  70. }
  71. # List of subcommand button bindings (key name and underline position)
  72. my %subcmd_bind = (
  73. BRANCH => {KEY => '<Alt-Key-b>', U => 0},
  74. CHECKOUT => {KEY => '<Alt-Key-o>', U => 5},
  75. STATUS => {KEY => '<Alt-Key-s>', U => 0},
  76. DIFF => {KEY => '<Alt-Key-d>', U => 0},
  77. ADD => {KEY => '<Alt-Key-a>', U => 0},
  78. DELETE => {KEY => '<Alt-Key-t>', U => 4},
  79. MERGE => {KEY => '<Alt-Key-m>', U => 0},
  80. CONFLICTS => {KEY => '<Alt-Key-f>', U => 3},
  81. COMMIT => {KEY => '<Alt-Key-c>', U => 0},
  82. UPDATE => {KEY => '<Alt-Key-u>', U => 0},
  83. SWITCH => {KEY => '<Alt-Key-w>', U => 1},
  84. );
  85. # List of subcommand variables
  86. my %subcmdvar = (
  87. CWD => cwd (),
  88. WCT => '',
  89. CWD_URL => '',
  90. WCT_URL => '',
  91. BRANCH => {
  92. OPT => 'info',
  93. URL => '',
  94. NAME => '',
  95. TYPE => 'DEV',
  96. REVFLAG => 'NORMAL',
  97. REV => '',
  98. TICKET => '',
  99. SRCTYPE => 'trunk',
  100. S_CHD => 0,
  101. S_SIB => 0,
  102. S_OTH => 0,
  103. VERBOSE => 0,
  104. OTHER => '',
  105. },
  106. CHECKOUT => {
  107. URL => '',
  108. REV => 'HEAD',
  109. PATH => '',
  110. OTHER => '',
  111. },
  112. STATUS => {
  113. USEWCT => 0,
  114. UPDATE => 0,
  115. VERBOSE => 0,
  116. OTHER => '',
  117. },
  118. DIFF => {
  119. USEWCT => 0,
  120. TOOL => 'graphical',
  121. BRANCH => 0,
  122. URL => '',
  123. OTHER => '',
  124. },
  125. ADD => {
  126. USEWCT => 0,
  127. CHECK => 1,
  128. OTHER => '',
  129. },
  130. DELETE => {
  131. USEWCT => 0,
  132. CHECK => 1,
  133. OTHER => '',
  134. },
  135. MERGE => {
  136. USEWCT => 1,
  137. SRC => '',
  138. MODE => 'automatic',
  139. DRYRUN => 0,
  140. VERBOSE => 0,
  141. REV => '',
  142. OTHER => '',
  143. },
  144. CONFLICTS => {
  145. USEWCT => 0,
  146. OTHER => '',
  147. },
  148. COMMIT => {
  149. USEWCT => 1,
  150. DRYRUN => 0,
  151. OTHER => '',
  152. },
  153. UPDATE => {
  154. USEWCT => 1,
  155. OTHER => '',
  156. },
  157. SWITCH => {
  158. USEWCT => 1,
  159. URL => '',
  160. OTHER => '',
  161. },
  162. );
  163. # List of action buttons
  164. my %action_b;
  165. # List of action button help strings
  166. my %action_help = (
  167. QUIT => 'Quit fcm gui',
  168. HELP => 'Print help to the output text box for the selected sub-command',
  169. CLEAR => 'Clear the output text box',
  170. RUN => 'Run the selected sub-command',
  171. );
  172. # List of action button bindings
  173. my %action_bind = (
  174. QUIT => {KEY => '<Control-Key-q>', U => undef},
  175. HELP => {KEY => '<F1>' , U => undef},
  176. CLEAR => {KEY => '<Alt-Key-l>' , U => 1},
  177. RUN => {KEY => '<Alt-Key-r>' , U => 0},
  178. );
  179. # List of branch subcommand options
  180. my %branch_opt = (
  181. INFO => undef,
  182. CREATE => undef,
  183. DELETE => undef,
  184. LIST => undef,
  185. );
  186. # List of branch create types
  187. my %branch_type = (
  188. 'DEV' => undef,
  189. 'DEV::SHARE' => undef,
  190. 'TEST' => undef,
  191. 'TEST::SHARE' => undef,
  192. 'PKG' => undef,
  193. 'PKG::SHARE' => undef,
  194. 'PKG::CONFIG' => undef,
  195. 'PKG::REL' => undef,
  196. );
  197. # List of branch create source type
  198. my %branch_srctype = (
  199. TRUNK => undef,
  200. BRANCH => undef,
  201. );
  202. # List of branch create revision prefix option
  203. my %branch_revflag = (
  204. NORMAL => undef,
  205. NUMBER => undef,
  206. NONE => undef,
  207. );
  208. # List of branch info/delete options
  209. my %branch_info_opt = (
  210. S_CHD => 'Show children',
  211. S_SIB => 'Show siblings',
  212. S_OTH => 'Show other',
  213. VERBOSE => 'Print extra information',
  214. );
  215. # List of diff display options
  216. my %diff_display_opt = (
  217. default => 'Default mode',
  218. graphical => 'Graphical tool',
  219. trac => 'Trac (only for diff relative to the base of the branch)',
  220. );
  221. # Text in the status bar
  222. my $statustext = '';
  223. # ------------------------------------------------------------------------------
  224. my $mw = MainWindow->new ();
  225. my $mw_title = 'FCM GUI';
  226. $mw->title ($mw_title);
  227. # Frame containing subcommand selection buttons
  228. my $top_f = $mw->Frame ()->grid (
  229. '-row' => 0,
  230. '-column' => 0,
  231. '-sticky' => 'w',
  232. );
  233. # Frame containing subcommand options
  234. my $mid_f = $mw->Frame ()->grid (
  235. '-row' => 1,
  236. '-column' => 0,
  237. '-sticky' => 'ew',
  238. );
  239. # Frame containing action buttons
  240. my $bot_f = $mw->Frame ()->grid (
  241. '-row' => 2,
  242. '-column' => 0,
  243. '-sticky' => 'ew',
  244. );
  245. # Text box to display output
  246. my $out_t = $mw->Scrolled ('ROText', '-scrollbars' => 'osow')->grid (
  247. '-row' => 3,
  248. '-column' => 0,
  249. '-sticky' => 'news',
  250. );
  251. # Text box - allow scroll with mouse wheel
  252. $out_t->bind (
  253. '<4>' => sub {
  254. $_[0]->yview ('scroll', -1, 'units') unless $Tk::strictMotif;
  255. },
  256. );
  257. $out_t->bind (
  258. '<5>' => sub {
  259. $_[0]->yview ('scroll', +1, 'units') unless $Tk::strictMotif;
  260. },
  261. );
  262. # Status bar
  263. $mw->Label (
  264. '-textvariable' => \$statustext,
  265. '-relief' => 'groove',
  266. )->grid (
  267. '-row' => 4,
  268. '-column' => 0,
  269. '-sticky' => 'ews',
  270. );
  271. # Main window grid configure
  272. {
  273. my ($cols, $rows) = $mw->gridSize ();
  274. $mw->gridColumnconfigure ($_, '-weight' => 1) for (0 .. $cols - 1);
  275. $mw->gridRowconfigure ( 3, '-weight' => 1);
  276. }
  277. # Frame grid configure
  278. {
  279. my ($cols, $rows) = $mid_f->gridSize ();
  280. $bot_f->gridColumnconfigure (3, '-weight' => 1);
  281. }
  282. $mid_f->gridRowconfigure (0, '-weight' => 1);
  283. $mid_f->gridColumnconfigure (0, '-weight' => 1);
  284. # ------------------------------------------------------------------------------
  285. # Buttons to select subcommands
  286. {
  287. my $col = 0;
  288. for my $name (@subcmds) {
  289. $subcmd_b{$name} = $top_f->Button (
  290. '-text' => uc (substr ($name, 0, 1)) . lc (substr ($name, 1)),
  291. '-command' => [\&button_clicked, $name],
  292. '-width' => 8,
  293. )->grid (
  294. '-row' => 0,
  295. '-column' => $col++,
  296. '-sticky' => 'w',
  297. );
  298. $subcmd_b{$name}->bind ('<Enter>', sub {$statustext = $subcmd_help{$name}});
  299. $subcmd_b{$name}->bind ('<Leave>', sub {$statustext = ''});
  300. $subcmd_b{$name}->configure ('-underline' => $subcmd_bind{$name}{U})
  301. if defined $subcmd_bind{$name}{U};
  302. $mw->bind ($subcmd_bind{$name}{KEY}, sub {$subcmd_b{$name}->invoke});
  303. }
  304. }
  305. # ------------------------------------------------------------------------------
  306. # Frames to contain subcommands options
  307. {
  308. my %row = ();
  309. for my $name (@subcmds) {
  310. $subcmd_f{$name} = $mid_f->Frame ();
  311. $subcmd_f{$name}->gridColumnconfigure (1, '-weight' => 1);
  312. $row{$name} = 0;
  313. # Widgets common to all sub-commands
  314. $subcmd_f{$name}->Label ('-text' => 'Current working directory: ')->grid (
  315. '-row' => $row{$name},
  316. '-column' => 0,
  317. '-sticky' => 'w',
  318. );
  319. $subcmd_f{$name}->Label ('-textvariable' => \($subcmdvar{CWD}))->grid (
  320. '-row' => $row{$name}++,
  321. '-column' => 1,
  322. '-sticky' => 'w',
  323. );
  324. }
  325. # Widgets common to all sub-commands that apply to working copies
  326. for my $name (@wco_subcmds) {
  327. my @labtxts = (
  328. 'Corresponding URL: ',
  329. 'Working copy top: ',
  330. 'Corresponding URL: ',
  331. );
  332. my @varrefs = \(
  333. $subcmdvar{URL_CWD},
  334. $subcmdvar{WCT},
  335. $subcmdvar{URL_WCT},
  336. );
  337. for my $i (0 .. $#varrefs) {
  338. $subcmd_f{$name}->Label ('-text' => $labtxts[$i])->grid (
  339. '-row' => $row{$name},
  340. '-column' => 0,
  341. '-sticky' => 'w',
  342. );
  343. $subcmd_f{$name}->Label ('-textvariable' => $varrefs[$i])->grid (
  344. '-row' => $row{$name}++,
  345. '-column' => 1,
  346. '-sticky' => 'w',
  347. );
  348. }
  349. $subcmd_f{$name}->Checkbutton (
  350. '-text' => 'Apply sub-command to working copy top',
  351. '-variable' => \($subcmdvar{$name}{USEWCT}),
  352. '-state' => (grep ({$_ eq $name} @wcto_subcmds) ? 'disabled' : 'normal'),
  353. )->grid (
  354. '-row' => $row{$name}++,
  355. '-column' => 0,
  356. '-columnspan' => 2,
  357. '-sticky' => 'w',
  358. );
  359. }
  360. # Widget for the Branch sub-command
  361. {
  362. my $name = 'BRANCH';
  363. # Radio buttons to select the sub-option of the branch sub-command
  364. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  365. '-row' => $row{$name}++,
  366. '-column' => 0,
  367. '-columnspan' => 2,
  368. '-sticky' => 'w',
  369. );
  370. my $col = 0;
  371. for my $key (sort keys %branch_opt) {
  372. my $opt = lc $key;
  373. $branch_opt{$key} = $opt_f->Radiobutton (
  374. '-text' => $opt,
  375. '-value' => $opt,
  376. '-variable' => \($subcmdvar{$name}{OPT}),
  377. '-state' => 'normal',
  378. )->grid (
  379. '-row' => 0,
  380. '-column' => $col++,
  381. '-sticky' => 'w',
  382. );
  383. }
  384. # Label and entry box for specifying URL
  385. $subcmd_f{$name}->Label ('-text' => 'URL: ')->grid (
  386. '-row' => $row{$name},
  387. '-column' => 0,
  388. '-sticky' => 'w',
  389. );
  390. $subcmd_f{$name}->Entry (
  391. '-textvariable' => \($subcmdvar{$name}{URL}),
  392. )->grid (
  393. '-row' => $row{$name}++,
  394. '-column' => 1,
  395. '-sticky' => 'ew',
  396. );
  397. # Label and entry box for specifying create branch name
  398. $subcmd_f{$name}->Label (
  399. '-text' => 'Branch name (create only): ',
  400. )->grid (
  401. '-row' => $row{$name},
  402. '-column' => 0,
  403. '-sticky' => 'w',
  404. );
  405. $subcmd_f{$name}->Entry (
  406. '-textvariable' => \($subcmdvar{$name}{NAME}),
  407. )->grid (
  408. '-row' => $row{$name}++,
  409. '-column' => 1,
  410. '-sticky' => 'ew',
  411. );
  412. # Label and entry box for specifying create branch source revision
  413. $subcmd_f{$name}->Label (
  414. '-text' => 'Source revision (create/list only): ',
  415. )->grid (
  416. '-row' => $row{$name},
  417. '-column' => 0,
  418. '-sticky' => 'w',
  419. );
  420. $subcmd_f{$name}->Entry (
  421. '-textvariable' => \($subcmdvar{$name}{REV}),
  422. )->grid (
  423. '-row' => $row{$name}++,
  424. '-column' => 1,
  425. '-sticky' => 'ew',
  426. );
  427. # Label and radio buttons box for specifying create branch type
  428. $subcmd_f{$name}->Label (
  429. '-text' => 'Branch type (create only): ',
  430. )->grid (
  431. '-row' => $row{$name},
  432. '-column' => 0,
  433. '-sticky' => 'w',
  434. );
  435. {
  436. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  437. '-row' => $row{$name}++,
  438. '-column' => 1,
  439. '-sticky' => 'w',
  440. );
  441. my $col = 0;
  442. for my $key (sort keys %branch_type) {
  443. my $txt = lc $key;
  444. my $opt = $key;
  445. $branch_opt{$key} = $opt_f->Radiobutton (
  446. '-text' => $txt,
  447. '-value' => $opt,
  448. '-variable' => \($subcmdvar{$name}{TYPE}),
  449. '-state' => 'normal',
  450. )->grid (
  451. '-row' => 0,
  452. '-column' => $col++,
  453. '-sticky' => 'w',
  454. );
  455. }
  456. }
  457. # Label and radio buttons box for specifying create source type
  458. $subcmd_f{$name}->Label (
  459. '-text' => 'Source type (create only): ',
  460. )->grid (
  461. '-row' => $row{$name},
  462. '-column' => 0,
  463. '-sticky' => 'w',
  464. );
  465. {
  466. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  467. '-row' => $row{$name}++,
  468. '-column' => 1,
  469. '-sticky' => 'w',
  470. );
  471. my $col = 0;
  472. for my $key (sort keys %branch_srctype) {
  473. my $txt = lc $key;
  474. my $opt = lc $key;
  475. $branch_opt{$key} = $opt_f->Radiobutton (
  476. '-text' => $txt,
  477. '-value' => $opt,
  478. '-variable' => \($subcmdvar{$name}{SRCTYPE}),
  479. '-state' => 'normal',
  480. )->grid (
  481. '-row' => 0,
  482. '-column' => $col++,
  483. '-sticky' => 'w',
  484. );
  485. }
  486. }
  487. # Label and radio buttons box for specifying create prefix option
  488. $subcmd_f{$name}->Label (
  489. '-text' => 'Prefix option (create only): ',
  490. )->grid (
  491. '-row' => $row{$name},
  492. '-column' => 0,
  493. '-sticky' => 'w',
  494. );
  495. {
  496. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  497. '-row' => $row{$name}++,
  498. '-column' => 1,
  499. '-sticky' => 'w',
  500. );
  501. my $col = 0;
  502. for my $key (sort keys %branch_revflag) {
  503. my $txt = lc $key;
  504. my $opt = $key;
  505. $branch_opt{$key} = $opt_f->Radiobutton (
  506. '-text' => $txt,
  507. '-value' => $opt,
  508. '-variable' => \($subcmdvar{$name}{REVFLAG}),
  509. '-state' => 'normal',
  510. )->grid (
  511. '-row' => 0,
  512. '-column' => $col++,
  513. '-sticky' => 'w',
  514. );
  515. }
  516. }
  517. # Label and entry box for specifying ticket number
  518. $subcmd_f{$name}->Label (
  519. '-text' => 'Related Trac ticket(s) (create only): ',
  520. )->grid (
  521. '-row' => $row{$name},
  522. '-column' => 0,
  523. '-sticky' => 'w',
  524. );
  525. $subcmd_f{$name}->Entry (
  526. '-textvariable' => \($subcmdvar{$name}{TICKET}),
  527. )->grid (
  528. '-row' => $row{$name}++,
  529. '-column' => 1,
  530. '-sticky' => 'ew',
  531. );
  532. # Check button for info/delete
  533. # --show-children, --show-siblings, --show-other, --verbose
  534. $subcmd_f{$name}->Label (
  535. '-text' => 'Options for info/delete only: ',
  536. )->grid (
  537. '-row' => $row{$name},
  538. '-column' => 0,
  539. '-sticky' => 'w',
  540. );
  541. {
  542. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  543. '-row' => $row{$name}++,
  544. '-column' => 1,
  545. '-sticky' => 'w',
  546. );
  547. my $col = 0;
  548. for my $key (sort keys %branch_info_opt) {
  549. $opt_f->Checkbutton (
  550. '-text' => $branch_info_opt{$key},
  551. '-variable' => \($subcmdvar{$name}{$key}),
  552. )->grid (
  553. '-row' => 0,
  554. '-column' => $col++,
  555. '-sticky' => 'w',
  556. );
  557. }
  558. }
  559. }
  560. # Widget for the Checkout sub-command
  561. {
  562. my $name = 'CHECKOUT';
  563. # Label and entry boxes for specifying URL and revision
  564. my @labtxts = (
  565. 'URL: ',
  566. 'Revision: ',
  567. 'Path: ',
  568. );
  569. my @varrefs = \(
  570. $subcmdvar{$name}{URL},
  571. $subcmdvar{$name}{REV},
  572. $subcmdvar{$name}{PATH},
  573. );
  574. for my $i (0 .. $#varrefs) {
  575. $subcmd_f{$name}->Label ('-text' => $labtxts[$i])->grid (
  576. '-row' => $row{$name},
  577. '-column' => 0,
  578. '-sticky' => 'w',
  579. );
  580. $subcmd_f{$name}->Entry (
  581. '-textvariable' => $varrefs[$i],
  582. )->grid (
  583. '-row' => $row{$name}++,
  584. '-column' => 1,
  585. '-sticky' => 'ew',
  586. );
  587. }
  588. }
  589. # Widget for the Status sub-command
  590. {
  591. my $name = 'STATUS';
  592. # Checkbuttons for various options
  593. my @labtxts = (
  594. 'Display update information',
  595. 'Print extra information',
  596. );
  597. my @varrefs = \(
  598. $subcmdvar{$name}{UPDATE},
  599. $subcmdvar{$name}{VERBOSE},
  600. );
  601. for my $i (0 .. $#varrefs) {
  602. $subcmd_f{$name}->Checkbutton (
  603. '-text' => $labtxts[$i],
  604. '-variable' => $varrefs[$i],
  605. )->grid (
  606. '-row' => $row{$name}++,
  607. '-column' => 0,
  608. '-columnspan' => 2,
  609. '-sticky' => 'w',
  610. );
  611. }
  612. }
  613. # Widget for the Diff sub-command
  614. {
  615. my $name = 'DIFF';
  616. my $entry;
  617. $subcmd_f{$name}->Checkbutton (
  618. '-text' => 'Show differences relative to the base of the branch',
  619. '-variable' => \($subcmdvar{$name}{BRANCH}),
  620. '-command' => sub {
  621. $entry->configure (
  622. '-state' => ($subcmdvar{$name}{BRANCH} ? 'normal' : 'disabled'),
  623. );
  624. },
  625. )->grid (
  626. '-row' => $row{$name}++,
  627. '-column' => 0,
  628. '-columnspan' => 2,
  629. '-sticky' => 'w',
  630. );
  631. # Label and radio buttons box for specifying tool
  632. $subcmd_f{$name}->Label (
  633. '-text' => 'Display diff in: ',
  634. )->grid (
  635. '-row' => $row{$name},
  636. '-column' => 0,
  637. '-sticky' => 'w',
  638. );
  639. {
  640. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  641. '-row' => $row{$name}++,
  642. '-column' => 1,
  643. '-sticky' => 'w',
  644. );
  645. my $col = 0;
  646. for my $key (qw/default graphical trac/) {
  647. my $txt = $diff_display_opt{$key};
  648. my $opt = $key;
  649. $branch_opt{$key} = $opt_f->Radiobutton (
  650. '-text' => $txt,
  651. '-value' => $opt,
  652. '-variable' => \($subcmdvar{$name}{TOOL}),
  653. '-state' => 'normal',
  654. )->grid (
  655. '-row' => 0,
  656. '-column' => $col++,
  657. '-sticky' => 'w',
  658. );
  659. }
  660. }
  661. $subcmd_f{$name}->Label ('-text' => 'Branch URL')->grid (
  662. '-row' => $row{$name},
  663. '-column' => 0,
  664. '-sticky' => 'w',
  665. );
  666. $entry = $subcmd_f{$name}->Entry (
  667. '-textvariable' => \($subcmdvar{$name}{URL}),
  668. '-state' => ($subcmdvar{$name}{BRANCH} ? 'normal' : 'disabled'),
  669. )->grid (
  670. '-row' => $row{$name}++,
  671. '-column' => 1,
  672. '-sticky' => 'ew',
  673. );
  674. }
  675. # Widget for the Add/Delete sub-command
  676. for my $name (qw/ADD DELETE/) {
  677. # Checkbuttons for various options
  678. $subcmd_f{$name}->Checkbutton (
  679. '-text' => 'Check for files or directories not under version control',
  680. '-variable' => \($subcmdvar{$name}{CHECK}),
  681. )->grid (
  682. '-row' => $row{$name}++,
  683. '-column' => 0,
  684. '-columnspan' => 2,
  685. '-sticky' => 'w',
  686. );
  687. }
  688. # Widget for the Merge sub-command
  689. {
  690. my $name = 'MERGE';
  691. # Label and radio buttons box for specifying merge mode
  692. $subcmd_f{$name}->Label (
  693. '-text' => 'Mode: ',
  694. )->grid (
  695. '-row' => $row{$name},
  696. '-column' => 0,
  697. '-sticky' => 'w',
  698. );
  699. {
  700. my $opt_f = $subcmd_f{$name}->Frame ()->grid (
  701. '-row' => $row{$name}++,
  702. '-column' => 1,
  703. '-sticky' => 'w',
  704. );
  705. my $col = 0;
  706. for my $key (qw/automatic custom reverse/) {
  707. my $txt = lc $key;
  708. my $opt = $key;
  709. $branch_opt{$key} = $opt_f->Radiobutton (
  710. '-text' => $txt,
  711. '-value' => $opt,
  712. '-variable' => \($subcmdvar{$name}{MODE}),
  713. '-state' => 'normal',
  714. )->grid (
  715. '-row' => 0,
  716. '-column' => $col++,
  717. '-sticky' => 'w',
  718. );
  719. }
  720. }
  721. # Check buttons for dry-run
  722. $subcmd_f{$name}->Checkbutton (
  723. '-text' => 'Dry run',
  724. '-variable' => \($subcmdvar{$name}{DRYRUN}),
  725. )->grid (
  726. '-row' => $row{$name}++,
  727. '-column' => 0,
  728. '-columnspan' => 2,
  729. '-sticky' => 'w',
  730. );
  731. # Check buttons for verbose mode
  732. $subcmd_f{$name}->Checkbutton (
  733. '-text' => 'Print extra information',
  734. '-variable' => \($subcmdvar{$name}{VERBOSE}),
  735. )->grid (
  736. '-row' => $row{$name}++,
  737. '-column' => 0,
  738. '-columnspan' => 2,
  739. '-sticky' => 'w',
  740. );
  741. # Label and entry boxes for specifying merge source
  742. $subcmd_f{$name}->Label (
  743. '-text' => 'Source (automatic/custom only): ',
  744. )->grid (
  745. '-row' => $row{$name},
  746. '-column' => 0,
  747. '-sticky' => 'w',
  748. );
  749. $subcmd_f{$name}->Entry (
  750. '-textvariable' => \($subcmdvar{$name}{SRC}),
  751. )->grid (
  752. '-row' => $row{$name}++,
  753. '-column' => 1,
  754. '-sticky' => 'ew',
  755. );
  756. # Label and entry boxes for specifying merge revision (range)
  757. $subcmd_f{$name}->Label (
  758. '-text' => 'Revision (custom/reverse only): ',
  759. )->grid (
  760. '-row' => $row{$name},
  761. '-column' => 0,
  762. '-sticky' => 'w',
  763. );
  764. $subcmd_f{$name}->Entry (
  765. '-textvariable' => \($subcmdvar{$name}{REV}),
  766. )->grid (
  767. '-row' => $row{$name}++,
  768. '-column' => 1,
  769. '-sticky' => 'ew',
  770. );
  771. }
  772. # Widget for the Commit sub-command
  773. {
  774. my $name = 'COMMIT';
  775. # Checkbuttons for various options
  776. $subcmd_f{$name}->Checkbutton (
  777. '-text' => 'Dry run',
  778. '-variable' => \($subcmdvar{$name}{DRYRUN}),
  779. )->grid (
  780. '-row' => $row{$name}++,
  781. '-column' => 0,
  782. '-columnspan' => 2,
  783. '-sticky' => 'w',
  784. );
  785. }
  786. # Widget for the Switch sub-command
  787. {
  788. my $name = 'SWITCH';
  789. # Label and entry boxes for specifying switch URL
  790. $subcmd_f{$name}->Label ('-text' => 'URL: ')->grid (
  791. '-row' => $row{$name},
  792. '-column' => 0,
  793. '-sticky' => 'w',
  794. );
  795. $subcmd_f{$name}->Entry (
  796. '-textvariable' => \($subcmdvar{$name}{URL}),
  797. )->grid (
  798. '-row' => $row{$name}++,
  799. '-column' => 1,
  800. '-sticky' => 'ew',
  801. );
  802. }
  803. # Widgets common to all sub-commands
  804. for my $name (@subcmds) {
  805. $subcmd_f{$name}->Label ('-text' => 'Other options: ')->grid (
  806. '-row' => $row{$name},
  807. '-column' => 0,
  808. '-sticky' => 'w',
  809. );
  810. $subcmd_f{$name}->Entry (
  811. '-textvariable' => \($subcmdvar{$name}{OTHER}),
  812. )->grid (
  813. '-row' => $row{$name}++,
  814. '-column' => 1,
  815. '-sticky' => 'ew',
  816. );
  817. }
  818. }
  819. # ------------------------------------------------------------------------------
  820. # Buttons to perform main actions
  821. {
  822. my $col = 0;
  823. for my $name (qw/QUIT HELP CLEAR RUN/) {
  824. $action_b{$name} = $bot_f->Button (
  825. '-text' => uc (substr ($name, 0, 1)) . lc (substr ($name, 1)),
  826. '-command' => [\&button_clicked, $name],
  827. '-width' => 8,
  828. )->grid (
  829. '-row' => 0,
  830. '-column' => $col++,
  831. '-sticky' => ($name eq 'RUN' ? 'ew' : 'w'),
  832. );
  833. $action_b{$name}->bind ('<Enter>', sub {$statustext = $action_help{$name}});
  834. $action_b{$name}->bind ('<Leave>', sub {$statustext = ''});
  835. $action_b{$name}->configure ('-underline' => $action_bind{$name}{U})
  836. if defined $action_bind{$name}{U};
  837. $mw->bind ($action_bind{$name}{KEY}, sub {$action_b{$name}->invoke});
  838. }
  839. }
  840. &change_cwd ($subcmdvar{CWD});
  841. # ------------------------------------------------------------------------------
  842. # Handle the situation when the user attempts to quit the window while a
  843. # sub-command is running
  844. $mw->protocol ('WM_DELETE_WINDOW', sub {
  845. if (defined $cmdpid) {
  846. my $ans = $mw->messageBox (
  847. '-title' => $mw_title,
  848. '-message' => $selsubcmd . ' is still running. Really quit?',
  849. '-type' => 'YesNo',
  850. '-default' => 'No',
  851. );
  852. if ($ans eq 'Yes') {
  853. kill 9, $cmdpid; # Need to kill the sub-process before quitting
  854. } else {
  855. return; # Do not quit
  856. }
  857. }
  858. exit;
  859. });
  860. MainLoop;
  861. # ------------------------------------------------------------------------------
  862. # SYNOPSIS
  863. # &change_cwd ($dir);
  864. #
  865. # DESCRIPTION
  866. # Change current working directory to $dir
  867. # ------------------------------------------------------------------------------
  868. sub change_cwd {
  869. my $dir = $_[0];
  870. my @allowed_subcmds = (&is_wc ($dir) ? @wc_subcmds : @nwc_subcmds);
  871. for my $subcmd (@subcmds) {
  872. if (grep {$_ eq $subcmd} @allowed_subcmds) {
  873. $subcmd_b{$subcmd}->configure ('-state' => 'normal');
  874. } else {
  875. $subcmd_b{$subcmd}->configure ('-state' => 'disabled');
  876. }
  877. }
  878. &display_subcmd_frame ($allowed_subcmds[0])
  879. if not grep {$_ eq $selsubcmd} @allowed_subcmds;
  880. chdir $dir;
  881. $subcmdvar{CWD} = $dir;
  882. if (&is_wc ($dir)) {
  883. $subcmdvar{WCT} = &get_wct ($dir);
  884. $subcmdvar{URL_CWD} = &get_url_of_wc ($dir);
  885. $subcmdvar{URL_WCT} = &get_url_of_wc ($subcmdvar{WCT});
  886. $branch_opt{INFO} ->configure ('-state' => 'normal');
  887. $branch_opt{DELETE}->configure ('-state' => 'normal');
  888. $subcmdvar{BRANCH}{OPT} = 'info';
  889. } else {
  890. $branch_opt{INFO} ->configure ('-state' => 'disabled');
  891. $branch_opt{DELETE}->configure ('-state' => 'disabled');
  892. $subcmdvar{BRANCH}{OPT} = 'create';
  893. }
  894. return;
  895. }
  896. # ------------------------------------------------------------------------------
  897. # SYNOPSIS
  898. # &button_clicked ($name);
  899. #
  900. # DESCRIPTION
  901. # Call back function to handle a click on a command button named $name.
  902. # ------------------------------------------------------------------------------
  903. sub button_clicked {
  904. my $name = $_[0];
  905. if (grep {$_ eq $name} keys %subcmd_b) {
  906. &display_subcmd_frame ($name);
  907. } elsif ($name eq 'CLEAR') {
  908. $out_t->delete ('1.0', 'end');
  909. } elsif ($name eq 'QUIT') {
  910. exit;
  911. } elsif ($name eq 'HELP') {
  912. &invoke_cmd ('help ' . lc ($selsubcmd));
  913. } elsif ($name eq 'RUN') {
  914. &invoke_cmd (&setup_cmd ($selsubcmd));
  915. } else {
  916. $out_t->insert ('end', $name . ': function to be implemented' . "\n");
  917. $out_t->yviewMoveto (1);
  918. }
  919. return;
  920. }
  921. # ------------------------------------------------------------------------------
  922. # SYNOPSIS
  923. # &display_subcmd_frame ($name);
  924. #
  925. # DESCRIPTION
  926. # Change selected subcommand to $name, and display the frame containing the
  927. # widgets for configuring the options and arguments of that subcommand.
  928. # ------------------------------------------------------------------------------
  929. sub display_subcmd_frame {
  930. my $name = $_[0];
  931. if ($selsubcmd ne $name and not $cmdrunning) {
  932. $subcmd_b{$name }->configure ('-relief' => 'sunken');
  933. $subcmd_b{$selsubcmd}->configure ('-relief' => 'raised') if $selsubcmd;
  934. $subcmd_f{$name }->grid ('-sticky' => 'new');
  935. $subcmd_f{$selsubcmd}->gridForget if $selsubcmd;
  936. $selsubcmd = $name;
  937. }
  938. return;
  939. }
  940. # ------------------------------------------------------------------------------
  941. # SYNOPSIS
  942. # $pos = &get_wm_pos ();
  943. #
  944. # DESCRIPTION
  945. # Returns the position part of the geometry string of the main window.
  946. # ------------------------------------------------------------------------------
  947. sub get_wm_pos {
  948. my $geometry = $mw->geometry ();
  949. $geometry =~ /^=?(?:\d+x\d+)?([+-]\d+[+-]\d+)$/;
  950. return $1;
  951. }
  952. # ------------------------------------------------------------------------------
  953. # SYNOPSIS
  954. # $command = &setup_cmd ($name);
  955. #
  956. # DESCRIPTION
  957. # Setup the the system command for the sub-command $name.
  958. # ------------------------------------------------------------------------------
  959. sub setup_cmd {
  960. my $name = $_[0];
  961. my $cmd = '';
  962. if ($name eq 'BRANCH') {
  963. $cmd .= lc ($name);
  964. if ($subcmdvar{$name}{OPT} eq 'create') {
  965. $cmd .= ' -c --svn-non-interactive';
  966. $cmd .= ' -n ' . $subcmdvar{$name}{NAME} if $subcmdvar{$name}{NAME};
  967. $cmd .= ' -t ' . $subcmdvar{$name}{TYPE};
  968. $cmd .= ' --rev-flag ' . $subcmdvar{$name}{REVFLAG};
  969. $cmd .= ' -r ' . $subcmdvar{$name}{REV} if $subcmdvar{$name}{REV};
  970. $cmd .= ' -k ' . $subcmdvar{$name}{TICKET} if $subcmdvar{$name}{TICKET};
  971. $cmd .= ' --branch-of-branch ' if $subcmdvar{$name}{SRCTYPE} eq 'branch';
  972. } elsif ($subcmdvar{$name}{OPT} eq 'delete') {
  973. $cmd .= ' -v' if $subcmdvar{$name}{VERBOSE};
  974. $cmd .= ' -d --svn-non-interactive';
  975. } elsif ($subcmdvar{$name}{OPT} eq 'list') {
  976. $cmd .= ' -l';
  977. $cmd .= ' -r ' . $subcmdvar{$name}{REV} if $subcmdvar{$name}{REV};
  978. } else {
  979. $cmd .= ' -i';
  980. $cmd .= ' --show-children' if $subcmdvar{$name}{S_CHD};
  981. $cmd .= ' --show-siblings' if $subcmdvar{$name}{S_SIB};
  982. $cmd .= ' --show-other' if $subcmdvar{$name}{S_OTH};
  983. $cmd .= ' -v' if $subcmdvar{$name}{VERBOSE};
  984. }
  985. $cmd .= ' ' . $subcmdvar{$name}{URL} if $subcmdvar{$name}{URL};
  986. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  987. } elsif ($name eq 'CHECKOUT') {
  988. $cmd .= lc ($name);
  989. $cmd .= ' -r' . $subcmdvar{$name}{REV} if $subcmdvar{$name}{REV};
  990. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  991. $cmd .= ' ' . $subcmdvar{$name}{URL};
  992. $cmd .= ' ' . $subcmdvar{$name}{PATH} if $subcmdvar{$name}{PATH};
  993. } elsif ($name eq 'STATUS') {
  994. $cmd .= lc ($name);
  995. $cmd .= ' -u' if $subcmdvar{$name}{UPDATE};
  996. $cmd .= ' -v' if $subcmdvar{$name}{VERBOSE};
  997. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  998. } elsif ($name eq 'DIFF') {
  999. $cmd .= lc ($name);
  1000. $cmd .= ' -g' if $subcmdvar{$name}{TOOL} eq 'graphical';
  1001. if ($subcmdvar{$name}{BRANCH}) {
  1002. $cmd .= ' -b';
  1003. $cmd .= ' -t' if $subcmdvar{$name}{TOOL} eq 'trac';
  1004. $cmd .= ' ' . $subcmdvar{$name}{URL} if $subcmdvar{$name}{URL};
  1005. }
  1006. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1007. } elsif ($name eq 'ADD' or $name eq 'DELETE') {
  1008. $cmd .= lc ($name);
  1009. $cmd .= ' -c' if $subcmdvar{$name}{CHECK};
  1010. $cmd .= ' --non-interactive'
  1011. if $name eq 'DELETE' and not $subcmdvar{$name}{CHECK};
  1012. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1013. } elsif ($name eq 'MERGE') {
  1014. $cmd .= lc ($name);
  1015. if ($subcmdvar{$name}{MODE} ne 'automatic') {
  1016. $cmd .= ' --' . $subcmdvar{$name}{MODE};
  1017. $cmd .= ' --revision ' . $subcmdvar{$name}{REV} if $subcmdvar{$name}{REV};
  1018. }
  1019. $cmd .= ' --dry-run' if $subcmdvar{$name}{DRYRUN};
  1020. $cmd .= ' -v' if $subcmdvar{$name}{VERBOSE};
  1021. $cmd .= ' ' . $subcmdvar{$name}{SRC} if $subcmdvar{$name}{SRC};
  1022. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1023. } elsif ($name eq 'CONFLICTS') {
  1024. $cmd .= lc ($name);
  1025. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1026. } elsif ($name eq 'COMMIT') {
  1027. $cmd .= lc ($name);
  1028. $cmd .= ' --dry-run' if $subcmdvar{$name}{DRYRUN};
  1029. $cmd .= ' --svn-non-interactive';
  1030. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1031. } elsif ($name eq 'SWITCH') {
  1032. $cmd .= lc ($name);
  1033. $cmd .= ' ' . $subcmdvar{$name}{URL} if $subcmdvar{$name}{URL};
  1034. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1035. } elsif ($name eq 'UPDATE') {
  1036. $cmd .= lc ($name);
  1037. $cmd .= ' ' . $subcmdvar{$name}{OTHER} if $subcmdvar{$name}{OTHER};
  1038. }
  1039. return $cmd;
  1040. }
  1041. # ------------------------------------------------------------------------------
  1042. # SYNOPSIS
  1043. # &invoke_cmd ($cmd);
  1044. #
  1045. # DESCRIPTION
  1046. # Invoke the command $cmd.
  1047. # ------------------------------------------------------------------------------
  1048. sub invoke_cmd {
  1049. my $cmd = $_[0];
  1050. return unless $cmd;
  1051. my $disp_cmd = 'fcm ' . $cmd;
  1052. $cmd = (index ($cmd, 'help ') == 0)
  1053. ? $disp_cmd
  1054. : ('fcm gui-internal ' . &get_wm_pos () . ' ' . $cmd);
  1055. # Change directory to working copy top if necessary
  1056. if ($subcmdvar{$selsubcmd}{USEWCT} and $subcmdvar{WCT} ne $subcmdvar{CWD}) {
  1057. chdir $subcmdvar{WCT};
  1058. $out_t->insert ('end', 'cd ' . $subcmdvar{WCT} . "\n");
  1059. $out_t->yviewMoveto (1);
  1060. }
  1061. # Report start of command
  1062. $out_t->insert ('end', timestamp_command ($disp_cmd, 'Start'));
  1063. $out_t->yviewMoveto (1);
  1064. # Open the command as a pipe
  1065. if ($cmdpid = open CMD, '-|', $cmd . ' 2>&1') {
  1066. # Disable all action buttons
  1067. $action_b{$_}->configure ('-state' => 'disabled') for (keys %action_b);
  1068. $cmdrunning = 1;
  1069. # Set up a file event to read output from the command
  1070. $mw->fileevent (\*CMD, readable => sub {
  1071. if (sysread CMD, my ($buf), 1024) {
  1072. # Insert text into the output text box as it becomes available
  1073. $out_t->insert ('end', $buf);
  1074. $out_t->yviewMoveto (1);
  1075. } else {
  1076. # Delete the file event and close the file when the command finishes
  1077. $mw->fileevent(\*CMD, readable => '');
  1078. close CMD;
  1079. $cmdpid = undef;
  1080. # Check return status
  1081. if ($?) {
  1082. $out_t->insert (
  1083. 'end', '"' . $disp_cmd . '" failed (' . $? . ')' . "\n",
  1084. );
  1085. $out_t->yviewMoveto (1);
  1086. }
  1087. # Report end of command
  1088. $out_t->insert ('end', timestamp_command ($disp_cmd, 'End'));
  1089. $out_t->yviewMoveto (1);
  1090. # Change back to CWD if necessary
  1091. if ($subcmdvar{$selsubcmd}{USEWCT} and
  1092. $subcmdvar{WCT} ne $subcmdvar{CWD}) {
  1093. chdir $subcmdvar{CWD};
  1094. $out_t->insert ('end', 'cd ' . $subcmdvar{CWD} . "\n");
  1095. $out_t->yviewMoveto (1);
  1096. }
  1097. # Enable all action buttons again
  1098. $action_b{$_}->configure ('-state' => 'normal') for (keys %action_b);
  1099. $cmdrunning = 0;
  1100. # If the command is "checkout", change directory to working copy
  1101. if (lc ($selsubcmd) eq 'checkout' && $subcmdvar{CHECKOUT}{URL}) {
  1102. my $url = Fcm::Keyword::expand($subcmdvar{CHECKOUT}{URL});
  1103. my $dir = $subcmdvar{CHECKOUT}{PATH}
  1104. ? $subcmdvar{CHECKOUT}{PATH}
  1105. : basename $url;
  1106. $dir = File::Spec->rel2abs ($dir);
  1107. &change_cwd ($dir);
  1108. # If the command is "switch", change URL
  1109. } elsif (lc ($selsubcmd) eq 'switch') {
  1110. $subcmdvar{URL_CWD} = &get_url_of_wc ($subcmdvar{CWD}, 1);
  1111. $subcmdvar{URL_WCT} = &get_url_of_wc ($subcmdvar{WCT}, 1);
  1112. }
  1113. }
  1114. 1;
  1115. });
  1116. } else {
  1117. $mw->messageBox (
  1118. '-title' => 'Error',
  1119. '-message' => 'Error running "' . $cmd . '"',
  1120. '-icon' => 'error',
  1121. );
  1122. }
  1123. return;
  1124. }
  1125. # ------------------------------------------------------------------------------
  1126. __END__
  1127. =head1 NAME
  1128. fcm_gui
  1129. =head1 SYNOPSIS
  1130. fcm_gui [DIR]
  1131. =head1 DESCRIPTION
  1132. The fcm_gui command is a simple graphical user interface for some of the
  1133. commands of the FCM system. The optional argument DIR modifies the initial
  1134. working directory.
  1135. =head1 COPYRIGHT
  1136. (C) Crown copyright Met Office. All rights reserved.
  1137. =cut