summaryrefslogtreecommitdiff
path: root/biblio/bibtex/utils/tkbibtex/tkbibtex
blob: 83e9687dc8cfece9763e84f8de62fb09524d15b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
#! /bin/sh
# the next line restarts using wish \
exec wish $0 ${1+"$@"}

#---------------------------------------------------------------------------
# tkbibtex - a BibTeX file browser
# Copyright (c) 1997 Peter Corke	pic@cat.csiro.au
#  with major modifications by Guenter Milde (G.Milde@physik.tu-dresden.de)
# 
# Needs Tcl/Tk version 8.0 or later
#
# tkbibtex home page at
#    http://www.cat.csiro.au/cmst/staff/pic/tkbibtex.html
#
#  This is RELEASE 8 July 2000
#
set release 9
#
#---------------------------------------------------------------------------
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#---------------------------------------------------------------------------
# Contributors:
#	Guenter Milde (G.Milde@physik.tu-dresden.de)
#	John Fulton <John.Fulton@iname.com>
#	Thomas Henlich <henlich@mmers1.mw.tu-dresden.de>
#
# COMMAND LINE SWITCHES:
# ~~~~~~~~~~~~~~~~~~~~~
set usage {Usage: tkbibtex [switches] [bibfile]
   
   A browser/editor for BibTeX format bibliografy files
   
   * General switches:
   
   SWITCH	ARG	DESCRIPTION
   TYPE
   
   -debug int	0 = none, 1=moderate, 2=lots, ...
   -lyx  	string	name of pipe to connect to LyX with
   
   * For non-interactive searching mode (entered if any of these switches given)
   
   -search	string	search string (defaults to all)
   -type	string	reference type to search (defaults to all)
   -field	string	field to search (defaults to all)
   -ys		int	starting year (inclusive) (defaults to 0)
   -ye		int	ending year (inclusive) (defaults to 9999)
   -last	int	ending year is this year, starting year is specified
   number of years earlier
   -exact		case sensitive search
   -case		case sensitive search
by default will list the BibTeX source of the matching entries to stdout, but

   -count	will output number of matches only, not BibTeX source
   -list        will display a one line summary (key, type, title)
                        per match

Copyright (c) Peter Corke 1997-2000

   }

## user alterable inits, you may set/override these also in a file ~/.tkbibtexrc

#	default for ignore case check button in search window
set search_ignore_case 1
#       which fields shall have a folding multiple line entry?
set bigfields "annote title abstract"
#	number of lines in big fields
set title_lines_big     4
set annote_lines_big	10
set abstract_lines_big	10
set delete_confirm	true

# cite_grouping, controls how a list of references is pushed to LyX
#	false		[ref1][ref2][ref3]
#	true		[ref1,ref2,ref3]
set cite_grouping	true

# citekey_lower, controls whether all cite keys are made lower case. bibtex
# ignores case, so this is useful to detect duplicates.
set citekey_lower	false
#	name of strings file, searched for along BIBPATH
set strfile "strings.bib"
#	initial height of references (main) window (in chars)
set refs_height 30
#	initial width of references window (in chars)
set refs_width 30
# initial width of entries in browse window (in chars)
set entrywidth 75
# maximal number of backup copies: 0 = no backups, -1 unlimited
set backup_max 9
# default for new entries
set reftype_default "article"

# load user's init file if it exists
if {[file exists "~/.tkbibtexrc"]} {
   source "~/.tkbibtexrc"
}


# get BIBPATH environment variable if it exists
if {[info exists env(BIBPATH)]} {
   set bibpath $env(BIBPATH)
   set bibpathlist [split $bibpath :]
} else {
   set bibpathlist ""
}

## initializations, modify with caution
set curkey ""      ;# keyword of the entry shown in the .browse window
                    # or "" if there is no .browse window
set debug 0        ;# verbosity level 0,...,3  for debugging 
set bibchanged 0		
trace variable bibchanged w bibchange_proc
set citelist ""
set window_state ""
set curreftype ""
set fname "<noname>"
set global_print_cmd "|lpr"

foreach i $bigfields {set ${i}_big 0} ;# big_lentries folded to one line

# initial values of command params that may be set by command line switches
set arg_ys 0
set arg_ye 9999
set arg_search 9999
set arg_reftype "All"
set arg_field  "All"
set arg_search  ".*"
set arg_ignorecase   1
set arg_count   0
set command_line_mode 0
set LyXpipe $env(HOME)/.lyxpipe

# global bindings
bind Button <Up> {tkTabToWindow [tk_focusPrev %W]}
bind Button <Down> {tkTabToWindow [tk_focusNext %W]}
bind Button <Left> {tkTabToWindow [tk_focusPrev %W]}
bind Button <Right> {tkTabToWindow [tk_focusNext %W]}

bind all <F1> {briefhelp Keys}
bind all <Control-d> {edit_item duplicate}
bind all <Control-r> {edit_item rename}
bind all <Control-n> {edit_item new}
bind all <Control-f> {finditem}
bind all <Control-q> {quit}
bind all <Control-s> {savebib}
bind all <F2> {savebib}
bind all <Shift-F2> {saveasbib}
bind all <F3> {openbib}
bind all <Shift-F3> {closebib}


#---------------------------- DEFINES -------------------------------------
# define BibTeX reference types and fields, see btxdoc.[tex/bib] for 
# documentation

# common month names for the month menu
set months {jan feb mar apr may jun jul aug sep oct nov dec}

#---------------------------------------------------------------------
# The following lists tailor the operation of tkbibtex. 
# 1. to add a new reference type, say a BIGBOOK type, add the name (in l.c.)
#    to the list "alltypes"
# 2. to add a new field place the name in the lists "allfields" and:
# 3. to make it mandatory for a type add that field name to the
#    list  req(reftype).
# 4. to make it optional for a type add that field name to the
#    list  opt(reftype).
# 5. to make it an additional field (for all types) add that field name 
#    to the list ign (ignored fields)
#---------------------------------------------------------------------

# list of all fields
set allfields {address author booktitle chapter edition \
     editor howpublished institution journal month number \
     organization pages publisher school series title type volume \
  year note code url crossref annote abstract}

# list of all reference types
set alltypes {article book booklet inbook incollection \
     inproceedings manual mastersthesis misc phdthesis proceedings \
  techreport unpublished}

# list of additional fields, ignored by the standard BibTeX styles
set ign {crossref code url annote abstract}

# lists of required and optional fields for each reference type
set req(article) {author title journal year}
set opt(article) {volume number pages month note}

set req(book) {author title publisher year};# requires author OR editor
set opt(book) {editor volume number series address edition month note}

set req(booklet) {title}
set opt(booklet) {author howpublished address month year note}

set req(inbook) {author title chapter pages publisher year}
                #(requires author or editor)
set opt(inbook) {editor volume series address edition month note}

set req(incollection) {author title booktitle publisher year}
set opt(incollection) {editor volume number series type chapter \
                       pages address edition month note}

set req(inproceedings) {author title booktitle year}
set opt(inproceedings) {editor pages organization publisher address month note}

set req(manual) {title}
set opt(manual) {author organization address edition month year note}

set req(misc) {}
set opt(misc) {title author howpublished month year note}

set req(mastersthesis) {author title school year}
set opt(mastersthesis) {address month note}

set req(phdthesis) {author title school year}
set opt(phdthesis) {address month note}

set req(proceedings) {title year}
set opt(proceedings) {editor publisher organization address month note}

set req(techreport) {author title institution year}
set opt(techreport) {type number address month note}

set req(unpublished) {author title note}
set opt(unpublished) {month year}

#-------------------------- Datastructures -----------------------------
#
# Datastructures are somewhat limited in Tcl.  The two main ones are:
#
#	citelist	a list of all citations in the order they
#			 are displayed in the main listbox
#	REFLIST		an array in which the first index is the citation key,
#			 and the second index is the field.  Thus
#			 REFLIST(Corke87b,type) = "article"
#			 REFLIST(Corke87b,title) = "Yet another paper about..."
#

#----------------------- BibTeX format file i/o -----------------------------

# return full path name for specified file along BIBPATH
proc find_on_path {fname} {
   global	bibpathlist
   
   if {[file exists $fname]} {
         return $fname
   }
   	
   foreach p $bibpathlist {
      if {[file exists $p/$fname]} {
         set fname $p/$fname
         return $fname
      }
   }
   return {}
}

#
# parse the BibTeX format file and update the multidimensional array REFLIST.
#
proc bibparse {fname} {
   global citelist errmsg
   
   showmsg "loading $fname"
   . config -cursor watch
   trace vdelete REFLIST w REFLISTchange_proc
   set dupcount [bibparse_f $fname]
   trace variable REFLIST w REFLISTchange_proc
   set REFLIST_update 0
   update_citelistbox
   
   . config -cursor ""
   set count [llength $citelist]
   if {$dupcount == 0} {
      showmsg "$count records"
   } else {
      showmsg "$count records ($dupcount duplicates)"
   }
   testoutput 1 "$count records ($dupcount duplicates)"
   if {$errmsg != ""} {
      tk_messageBox -icon warning -type ok -message $errmsg
      set errmsg ""
   }

}

# --------  new parsing-algorithm by GM (rparse.tcl) --------------

set preamblelist ""
set errmsg ""

# core file parser

proc bibparse_f {fname} {

   global errmsg

   set f [open $fname r]
   
   testoutput 1 "loading $fname"
   showmsg  "loading $fname"

   set buffer [read $f]
   close $f

   testoutput 1 "parsing $fname"
   showmsg  "parsing $fname"

   return [bibparse_s $buffer]
}
   
proc bibparse_s {buffer} {
   # transform, to get a string that can be parsed by tcl-routines:

   # We have to cheat to get tcl parsing a bibtex file: BibTeX uses special 
   # characters to separate entries and fields. But inside a {string}
   # or a "string" they are escaped. This escaping is not regarded by "split"
   # or "regexp", but it is implemented in Tcl's list functions, 
   # however assuming a space as separating character
      
   # 1. escape backslashes (to prevent substitution of LaTeX-commands as 
   # there is one round of backslash substitution when the list element is not
   # enclosed in braces) and quote whitespace

   set new_entry 0
   set count 0
   set dupcount 0
   set catch_msg ""

   regsub -all {\\} $buffer {\\\\} buffer
   regsub -all "\[\t\n ]+" $buffer {\ } buffer

   # 2. put in additional whitespace where we want a separation
   #    '@' separates entries, ',' separates fields,
   # 3. braces and quotes must be surrounded by whitespace, 
   #    otherwise list commands will produce errors

   regsub -all "\[@\{,]" $buffer { &} buffer
   regsub -all "\[\}]" $buffer {& } buffer
   regsub -all {"} $buffer { & } buffer ;# comment " only for syntax color
    
   testoutput 3 $buffer

   # now look at the entries
   foreach element $buffer {

      testoutput 3  "<$element>"
   
      # the first element after a reftype contains the fields
      if {$new_entry} {
         parse_fields $element $reftype
         if {$catch_msg != ""} {
            append errmsg "$catch_msg \n\
               The following record could not be parsed:\n  \
               <[ruecktrafo $element]> \n\n\
               You might have to fix your *.bib file! \
               (probabely use of \"quotes\" \
               to enclose fields with umlauts) \n\n"
         }   
         set new_entry 0
         set catch_msg ""
         continue
      }
      # look for reftype
      if [regexp {^@([a-zA-Z]+) ?(\(?)} $element match reftype parantheses] {
         set reftype [string tolower $reftype]
         incr count
         if {$count%10 == 0} { # show progress every tenth parsed entry
            showmsg "parsing: $count records"
         }
         testoutput 1  "\nNew entry:"
         if {$parantheses == "("} {
           append errmsg "cannot handle entry in parantheses (yet): $element\n"
           # Baustelle 
           # diese Klausel kann weg, wenn Klammern richtig behandelt werden
         } else { 
            set new_entry 1
         }    
         continue
      }
      # somethig else: warn user, as this will not be written back to file
      testoutput 2 "ignored: <$element>"
      if [regexp {[a-zA-Z]+} $element] {
         append errmsg "ignored text: [ruecktrafo $element]\n"
      }
   }
   return $dupcount
}


proc parse_fields {fields reftype} {

   global  preamblelist strlist citelist REFLIST errmsg citekey_lower
   upvar dupcount dupcount
   upvar catch_msg catch_msg
   set pre_types {preamble string comment}
   set fieldtext 0
   set macro ""

   testoutput 3 $fields

   # store preambles, strings and comments to write them back 
   # when saving the file
   if {[lsearch $pre_types $reftype] >= 0 } {
      lappend preamblelist "@$reftype \{[ruecktrafo $fields]\}"
      testoutput 1  "pre-stuff: [lindex $preamblelist end]"
      if {$reftype == "string"} {
         # strings will be parsed and put to the stringlist although
         set keyw ""   ;# a string definiton has no keyword
      } else {      
         return 
      }
   }

   # process the fields
   # use catch, as the list might contain syntactic errors
   catch {
      foreach item $fields {
         testoutput 2  "<$item>"
         
         # first field is keyword (except for strings)
         if {![info exists keyw]} {
            set keyw [string trim $item]
	    if {$citekey_lower} {
		    set keyw [string tolower $keyw]
	    }
            # put in the Reflist
            set REFLIST($keyw,reftype) $reftype
            # if not already in the citelist, append it
            if {[lsearch -exact $citelist $keyw] < 0} {
               lappend citelist $keyw
            } else {
               # Baustelle: fragen: rename overwrite skip?
               set r [tk_dialog .duplicate {Duplicate!} \
                  "Cite key <$keyw> already exists" \
                  warning 0 {Skip} {Overwrite}]
               switch $r {
                  0 {incr dupcount; return}
                  1 {incr dupcount}
               }
            }
            testoutput 1  "$reftype $keyw"
            continue
         }
         
         # item is <"text"> or <{text}>
         if {$fieldtext} {
            set REFLIST($keyw,$fieldname) [ruecktrafo $item]
            set fieldtext 0
            testoutput 1 "  $fieldname   $REFLIST($keyw,$fieldname)"
            continue
         }
         
         # count for concatenations
         if [info exists concat] {
            testoutput 3 "concat = <$concat>"
            append REFLIST($keyw,$fieldname) "\{[ruecktrafo $item]\}"
            unset concat
            testoutput 1 "  $fieldname   $REFLIST($keyw,$fieldname)"
            continue
         }
         
         # item of the form <?,?fieldname = ?macro? ?#?>
         if [regexp {^,? ?([^ ]+) ?= ?(.*)} \
           $item match fieldname macro] {
            set fieldname [string tolower $fieldname]
            if {$macro != ""} {
               if [regexp {# ?$} $macro] {
                  set concat "#"
               }
               set REFLIST($keyw,$fieldname) "# $macro"
               testoutput 1 "  $fieldname  $REFLIST($keyw,$fieldname)"
               set macro ""
            } else {
               set fieldtext 1
            }
            continue
         }
         # concatenations < # ?macro? ?#?>
         if [regexp {^ ?(#.*)} $item match concat] {
            # if the first part is not a macro, put braces around
            if {![regexp {^#} $REFLIST($keyw,$fieldname)]} {
               set REFLIST($keyw,$fieldname) "#\{$REFLIST($keyw,$fieldname)\}"
            }
            append REFLIST($keyw,$fieldname) " $concat"
            testoutput 1 "  $fieldname  $REFLIST($keyw,$fieldname)"
            if {![regexp {# ?$} $concat]} {
               unset concat
            }
            continue
         }
         
         if {![regexp {^ *,? *$} $item]} {
            append errmsg "cannot parse <$item> \n"
         }
         
      } ;# ende {foreach {$fields}}...
   } catch_msg;# ende catch {foreach ....}

   if {$reftype == "string"} {
      set strlist($fieldname)  $REFLIST($keyw,$fieldname)
      unset REFLIST($keyw,$fieldname)
   }
   if [info exists keyw] {unset keyw}
}
# ende proc parse fields


proc ruecktrafo {string} {
   # 1. change back spaces
   regsub -all "(\}) " $string {\1} string
   regsub -all " (\[@\{,])" $string {\1} string
   regsub -all { (") } $string {\1} string      ;# "only for syntax color

   # Test what kind of string it is:
   # if it was in quotes, it will have spaces around -> remove
   # if the string was in braces  -> dequote it
   if {[regsub {^ (.*) $} $string {\1} string] == 0} {
      regsub -all {(\\)?\\} $string {\1} string
      } 
   return $string
}
 
# --------- end of stuff for the new parsing algorithm by GM ---------

proc update_citelistbox {} {
   global citelist
   
   # cream the old listbox contents
   .refs.list delete 0 end
   
   # now reinsert all items in citelist order
   foreach key $citelist {
      .refs.list insert end $key
   }
}

proc append_to_citelist {newkey} {
   global bibchanged citelist
   
   .refs.list insert end $newkey
   lappend citelist $newkey
   # note that we've updated the bib
   incr bibchanged		
}


# writebib	package
#
#	writebib citelist filename
#
#		writes specified citations to the given filename
#
#	writebib2str citelist
#
#		writes specified citations to the global buffer writebib_str
#		and also returns this string
#

proc writebib {citelist fname} {
   global debug
   
   showmsg "writing $fname"
   if {$debug} {
      puts "writing $fname"
   }
   . config -cursor watch
   set f [open $fname w]
   
   writebib2 $citelist fwrite $f
   close $f
   
   . config -cursor ""
   showmsg "[llength $citelist] entries written"
}

proc writebib2str {citelist} {
   global	writebib_str
   
   set writebib_str ""
   writebib2 $citelist swrite 0
   
   return $writebib_str
}

proc writebib2 {citelist wproc arg} {
   global REFLIST 
   
   foreach k $citelist {
      set rt $REFLIST($k,reftype)
      $wproc $arg "@$rt\{$k"
      
      set res [array get REFLIST "$k,*"]
      # now have a list comprising pairs of list elements; the REFLIST 
      # subscript then the value
      set nfound 0
      
      foreach {key val} $res {
         regexp {,([a-z]+)} $key matchall lastkey
         if {($lastkey != "reftype") && ($val != "")} {
            testoutput 1 "<$key $val$>"
            $wproc $arg ",\n"
            if {[regexp ^# $val]} {
               set val [string trimleft $val "#"]
               $wproc $arg "	$lastkey = $val"
            } else {
               $wproc $arg "	$lastkey = \{$val\}"
            }
         }
      }
      # put end of record brace
      $wproc $arg "\n\}\n\n"
   }
}

proc fwrite {f str} {
   puts -nonewline $f $str
}

proc swrite {f str} {
   global	writebib_str
   
   append writebib_str $str
}


#----------------------- BROWSE WINDOW -----------------------------------

# create the data entry window (.browse) with reftype menu and navigation bar
# (the fields will be inserted by set_browsebox)
proc create_browse {} {
   global alltypes curreftype reftype_default
   
   toplevel .browse
   build_stringmenu
   bind .browse <Destroy> {
     if {"%W" == ".browse"} {
         set curkey ""
         trace vdelete curreftype w reftypechange_proc
     }
   }
	bind .browse <Unmap> {wm_statechange %W}
	bind .browse <Map> {wm_statechange %W}
   # Reference type is a menu button whose current label shows the 
   # reference type.  Clicking brings up a radiobutton menu that allows
   # the type to change, and the browse box will reconfigure appropriately
   frame .browse.reftype
   label .browse.reftype.l -text "Reference type:" -width 15 -anchor e
   menubutton .browse.reftype.m -menu .browse.reftype.m.menu -width 20 \
      -relief raised -anchor w -text $reftype_default
   menu .browse.reftype.m.menu
   foreach i $alltypes {
      .browse.reftype.m.menu add radiobutton -label $i -variable curreftype \
         -value $i 
   }
   pack .browse.reftype.l .browse.reftype.m -side left -anchor w
   pack .browse.reftype  -expand 1 -anchor w
   
   # look for changes in the global curreftype
   trace variable curreftype w reftypechange_proc
   
   # a bottom line with helpful buttons:
   frame .browse.navigate
   button .browse.navigate.first -text {|<  First} -underline 4\
     -command {browseitem first .refs.list}
   button .browse.navigate.prev -text {<  Previous} -underline 3\
     -command {browseitem previous .refs.list}
   button .browse.navigate.next -text {Next  >} -underline 0\
     -command {browseitem next .refs.list}
   button .browse.navigate.last -text {Last  >|}  -underline 0\
     -command {browseitem last .refs.list}
   button .browse.navigate.close -text Close -width 10 -underline 0\
     -command {destroy .browse}
   button .browse.navigate.help -text Help -width 10 -underline 0\
     -command {briefhelp Browse}
   pack .browse.navigate.first .browse.navigate.prev .browse.navigate.next\
     .browse.navigate.last -side left -fill x -expand 1
   pack .browse.navigate.help .browse.navigate.close -side right
   pack .browse.navigate -side bottom -fill x
   bind .browse.navigate 1 {focus .browse.navigate}
   
   # bind the Alt + underlined keys
   bind .browse <Alt-Key-f> {browseitem first .refs.list; break}
   bind .browse <Alt-Key-p> {browseitem previous .refs.list; break}
   bind .browse <Alt-Key-n> {browseitem next .refs.list; break}
   bind .browse <Alt-Key-l> {browseitem last .refs.list; break}
   bind .browse <Alt-Key-c> {destroy .browse; break}
   bind .browse <Alt-Key-h> {briefhelp Browse; break}
}


# browse the specified cite key, optional arg "-focus" controls
#  whether the first item of .browse is focused on 
proc browse {name args} {
   global REFLIST allfields curkey curreftype curfields \
          bibchanged debug bigfields fname
   
   # ignore stupid keys 
   #   if {$name == ""} {return} ;# does this happen?
   
   # unset empty array elements of last browsed entry
   if {$curkey != ""} {
      trace vdelete REFLIST w REFLISTchange_proc
      foreach el [array names REFLIST $curkey,*] {
        if {$REFLIST($el) == ""} {unset REFLIST($el)}
      }
      trace vdelete REFLIST w REFLISTchange_proc
   }
  
   # set curkey to new value
   set curkey $name   

   # create browse window if need be and add the labeled entries for curreftype
   if {[winfo exists .browse] == 0} {
      create_browse
      set_browsebox $REFLIST($name,reftype)
   } 

   # configure the browse box with fields for this entry
   if {$curreftype != $REFLIST($name,reftype)} {
      # update curreftype: this calls set_browsebox and a rerun of browse 
      # via trace/curreftypechange_proc
      set curreftype $REFLIST($name,reftype)
      return
   } else {
      # delete non canonical fields (not predefined for this reference type)
      foreach i [lrange [pack slaves .browse] 2 end] {
         if [regexp {sep} $i] {continue}
         if {[lsearch $curfields [string range $i 8 end]] < 0} {destroy $i}
      }
   }
   # add nan canonical fields (not predefined but present in REFLIST)
   foreach el [array names REFLIST $name,*] {
      if [regexp {,([a-z]+)} $el matchall fieldname] {
         if {$fieldname == "reftype"} {continue}
         if {[lsearch $curfields $fieldname] < 0} {
            lentry $fieldname
         }
      }
   }
   
   # attach the entry to the browse box by textvariables, 
   # do special actions for big_lentry boxes
   foreach entry [lrange [pack slaves .browse] 2 end] {
      if [regexp {sep} $entry] {continue}
      set field [string range $entry 8 end]
      if {[lsearch $bigfields $field] >= 0} {
         .browse.$field.e delete 1.0 end
         if [info exists REFLIST($name,$field)] {
            .browse.$field.e insert 1.0 $REFLIST($name,$field)
         }
      } else {
         trace vdelete REFLIST w REFLISTchange_proc
         set in_reflist [info exists REFLIST($name,$field)]
         # now link entry box to data using textvariable
         .browse.$field.e config -textvariable REFLIST($name,$field)
         if {!$in_reflist} {
            .browse.$field.e delete 0 end
         }
         trace variable REFLIST w REFLISTchange_proc
      }
   }
   
   # put cite key into the titlebar
   wm title .browse "\[$fname\] $name"

   # set focus to first entry if called with option -focus
   # -force, as this is another toplevel window
   if { [lindex $args 0]  == "-focus"} {
      focus -force .browse.[lindex $curfields 0].e
   }    
}

# configure the browse window fields for specified reference type
proc set_browsebox {reftype} {
   global req opt ign

   # clear all old fields, (0st and 1st slave are reftype and navigate)
   foreach i [lrange [pack slaves .browse] 2 end] {
   #  pack forget $i ;
   # we better destroy and make anew, as this keeps the
   # right order for keybord traversal
      destroy $i
   }

   # add the new fields in right order, separate types with black lines
   foreach i $req($reftype) {
     lentry $i
   }
   frame .browse.sep1 -height 3 -background black
   pack .browse.sep1 -fill x -expand 1

   foreach i $opt($reftype) {
     lentry $i
   }
   frame .browse.sep2 -height 3 -background black
   pack .browse.sep2 -fill x -expand 1
   
   foreach i $ign {
     lentry $i
   }

}

# create a labelled entry box, a frame holding a label and an entry 
# (with multiple lines if name is mentionend in global $bigfields)
proc lentry {name} {
   global bigfields entrywidth months

   if {[winfo exists .browse.$name] == 0} {
      frame .browse.$name
      if {[lsearch $bigfields $name] >= 0} {
         button .browse.$name.l -text "[string toupper $name]:" -width 14 \
           -anchor e -default disabled -bd 1 -padx 2 -pady 0 \
           -highlightthickness 0 -takefocus 0 -command "fold_button {$name}"  
         text .browse.$name.e -yscrollcommand ".browse.$name.s set" -height 1 \
            -width 20
         bind .browse.$name.e <KeyRelease> "update_biglentry $name"
         bind .browse.$name.e <ButtonRelease> "update_biglentry $name"
         bind .browse.$name.e <Tab> {tkTabToWindow [tk_focusNext %W]; break}
         bind .browse.$name.e <Shift-Tab> {
                                     tkTabToWindow [tk_focusPrev %W]; break}
         bind .browse.$name.e <Up> {tkTextfieldUp %W}
         bind .browse.$name.e <Down> {tkTextfieldDown %W}
         # scrollbar will be displayed by proc fold_button if entry unfolded
         scrollbar .browse.$name.s -takefocus 0 -command ".browse.$name.e yview"
      } else {
         label .browse.$name.l -text "[string toupper $name]:" \
                               -width 15 -anchor e
         entry .browse.$name.e -width $entrywidth -insertofftime 0 
         bind .browse.$name.e <Up> {tkTabToWindow [tk_focusPrev %W]}
         bind .browse.$name.e <Down> {tkTabToWindow [tk_focusNext %W]}
         bind .browse.$name.e <Return> {tkTabToWindow [tk_focusNext %W]}
      }
      pack .browse.$name.l -side left
      pack .browse.$name.e -side left -fill x -expand 1
   }
   pack .browse.$name -fill x -expand 1

   # some special cases
   switch $name {
   month  {
	# bind right mouse button to string popup menu
	menu .browse.month.menu
	foreach i $months {
		.browse.month.menu add radiobutton -label $i -value #$i \
			 -command "month_menu_proc $i"
	}
	bind .browse.$name.e <Button-3> "month_popup %W %X %Y"
    }
   crossref {
	bind .browse.$name.e <Button-3> "crossrefGoto %W"
    }
   default {
	# bind right mouse button to string popup menu
	bind .browse.$name.e <Button-3> "string_popup %W %X %Y"
    }
   }

}

proc crossrefGoto {w} {
	set newkey [$w get]
	puts "going to $newkey"
	browse $newkey
}

proc fold_button {name} {
   global  ${name}_big ${name}_lines_big
   
   if [set ${name}_big] {
      .browse.$name.e config -height 1 -wrap none
      pack forget .browse.$name.s 
      set ${name}_big 0
   } else {
      .browse.$name.e config -height [set ${name}_lines_big] -wrap word
      pack .browse.$name.s -side right -fill y
      set ${name}_big 1
   }
}

# if cursor is on first line: move to previous window,
# otherwise the default binding works (move up one line)
# to be bound to <Key-Up> in a textfield inside a formular
proc tkTextfieldUp {w} {
   if {[$w index insert] == [tkTextUpDownLine $w -1]} {
      tkTabToWindow [tk_focusPrev $w]
      return break
   }
}

# if cursor is on last line: move to next window,
# otherwise the default binding works (move down one line)
# to be bound to <Key-Down> in a textfield inside a formular
proc tkTextfieldDown {w} {
   if {[$w index insert] == [tkTextUpDownLine $w 1]} {
      tkTabToWindow [tk_focusNext $w]
      return break  
   }
}


#invoked on right mouse button click in a month lentry box
proc month_popup {w x y} {
   global month_select
   
puts "<$x $y>"
   # pop-up the string menu
   tk_popup .browse.month.menu $x $y
   tkwait variable month_select
   $w insert insert $month_select
}

proc month_menu_proc {which} {
   global	month_select
   
puts "in month_menu_proc which = $which"
   set month_select "#$which"
}


#invoked on right mouse button click in a lentry box
proc string_popup {w x y} {
   global	string_select
   
   # pop-up the string menu
   tk_popup .browse.strmenu $x $y
   tkwait variable string_select
   $w insert insert $string_select

   # patch by Thomas Henlich henlich@mmers1.mw.tu-dresden.de
   set string_select ""
}

proc strmenu_proc {which} {
   global	string_select
   
   set string_select "#$which"
}

proc build_stringmenu {} {
   global	strlist
   
   menu .browse.strmenu
   foreach i [array names strlist] {
      .browse.strmenu add command -label $strlist($i) -command "strmenu_proc $i"
   }
}

# if global variable curreftype has changed: 
# invoke set_browsebox() and update REFLIST
proc reftypechange_proc {name el op} {
   global curreftype curkey REFLIST debug curfields req opt ign 
   
   set curfields [concat $req($curreftype) $opt($curreftype) $ign]
   .browse.reftype.m config -text $curreftype
   if {$REFLIST($curkey,reftype) != $curreftype} {
      set REFLIST($curkey,reftype) $curreftype
   }
   set_browsebox $curreftype
   browse $curkey
   testoutput 1 "reftype changing to $curreftype"
}

# as we cannot bind a textvariable to a text (only to an entry)
# make sure that the big fields displayed in the browse box are updated
# in the REFLIST.
# bound to <KeyRelease>, <ButtonRelease>
proc update_biglentry {fieldname} {
   global REFLIST curkey bibchanged
   set fieldtext [.browse.$fieldname.e get "1.0" end-1c]
   if {[info exists REFLIST($curkey,$fieldname)]} {
      # if fieldtext prev existed & has changed
      if {$fieldtext != $REFLIST($curkey,$fieldname)} {
         set REFLIST($curkey,$fieldname) $fieldtext
#         incr bibchanged # done by trace on REFLIST
      }
   } else {
      # no fieldtext in REFLIST, check if now finite
      if {$fieldtext != ""} {
         set REFLIST($curkey,$fieldname) $fieldtext
#         incr bibchanged
      }
   }
}

# if the bib data has changed flag that in the main title bar
proc REFLISTchange_proc {name el op} {
   global bibchanged 
   
   incr bibchanged
   #puts stdout "REFLIST $el changed, $bibchanged"
}

#
# if any widget changes the bibliography in any way it increments the global
# bibchanged.  This trace handler then takes the necessary action
#
proc bibchange_proc {name el op} {
   global bibchanged fname
   
   if {$bibchanged == 0} {
      wm title . [file tail $fname]
   } elseif {$bibchanged == 1} {
      wm title . "[file tail $fname] (mod)"
   }
   # clear the search window listbox
   if {[winfo exists .find]} {
      .find.list.lb delete 0 end
   }
}

#----------------------- SEARCH WINDOW -----------------------------------

# invoked to do the actual search
proc searchbib {} {
   global find_field searchstring citelist REFLIST  search_ignore_case
   global find_reftype find_startyear find_endyear
   
   . config -cursor watch
   
   # clear out the old entries in the results listbox
   .find.list.lb delete 0 end
   .find.m configure -text ""
   
   set found [do_search $searchstring $find_reftype $find_field $find_startyear $find_endyear $search_ignore_case]
   foreach f $found {
      .find.list.lb insert end $f
   }
   
   # display how many hits
   set nfound [llength $found]
   .find.m configure -text [format "%d match(es) found" $nfound]
   
   # put selection on first line of list box for next/prev buttons
   .find.list.lb selection set 0
   focus .find.list.lb

   . config -cursor ""
   
}

proc do_search {searchstring find_reftype find_field find_startyear find_endyear search_ignore_case} {
   global REFLIST citelist debug
   
   # convert search field to upper case and extract relevant (or all) fields
   if {$find_field != "All"} {
      set el $find_field
   }
   if {$search_ignore_case} {
      set search {regexp -nocase}
   } else {
      set search {regexp}
   }
   
   if {$debug} {
      puts "startyear: $find_startyear"
      puts "endyear: $find_endyear"
      puts "reftype: $find_reftype"
      puts "fieldtype: $find_field"
      puts "search : $searchstring"
      puts "LC test: $search"
   }
   
   
   # now we have a list comprising pairs of list elements:
   #  eg.  { Corke96a,TITLE   "blah blah blah" }
   set found {}
   
   foreach ref $citelist {
      # screen for reference type (which can be a regexp)
      if {$find_reftype != "All"} {
         if {[regexp -nocase $find_reftype $REFLIST($ref,reftype) mv] == 0} {
            continue;
         }
         if {$mv != $REFLIST($ref,reftype)} {
            continue
         }
      }
      
      # screen for year if its specified
      if {($find_startyear != "") || ($find_endyear != "")} {
         if {[info exists REFLIST($ref,year)]} {
            set year $REFLIST($ref,year)
            if {($find_endyear != "") && ($year > $find_endyear)} {
               continue
            }
            if {($find_startyear != "") && ($year < $find_startyear)} {
               continue
            }
         }
      }
      
      # now check particular field
      if {$find_field == "All"} {
         set res [array get REFLIST "$ref,*"]
         foreach {key val} $res {
            if {[eval $search $searchstring {$val}]} {
               #found substring
               lappend found $ref
               break
            }
         }
      } else {
         if {![info exists REFLIST($ref,$el)]} {
            continue
         }
         set w $REFLIST($ref,$el)
         testoutput 1 "$w"
         if {[eval $search $searchstring {$w}]} {
            #found substring
            lappend found $ref
         }
      }
   }
   return $found
}

# create the find/search box
proc create_find {} {
   global allfields alltypes find_field searchstring  search_ignore_case
   global find_reftype find_startyear find_endyear
   
   toplevel .find
   bind .find <Destroy> {
      destroy .find
      trace vdelete find_field w find_fieldchange_proc
      trace vdelete find_reftype w find_reftypechange_proc
   }
	bind .find <Unmap> {wm_statechange %W}
	bind .find <Map> {wm_statechange %W}
   #explaining Header
   wm title .find "find entries using regular expressions"
   
   ######################################################################
   # create the search entry boxes
   #	search string
   #	year range
   #	reference type
   
   ######################################################################
   # search string and ignore case button
   frame .find.str
   label .find.str.l -text "Search for:" -width 12 -anchor e -borderwidth 1
   entry .find.str.e -textvariable searchstring
   bind .find.str.e <Return> {searchbib}
   checkbutton .find.str.c -variable search_ignore_case -text "Ignore case"
   pack .find.str.l -side left
   pack .find.str.e  -fill x -expand 1 -side left
   pack .find.str.c  -expand 1 -side left
   pack .find.str -fill x -expand 1 -pady 2m
   
   ######################################################################
   # create a menu button for search type
   frame .find.field
   label .find.field.l -text "Field:" -width 12 -anchor e
   trace vdelete find_reftype w find_reftypechange_proc;# just in case still traced
   set find_field All
   
   menubutton .find.field.mb -menu .find.field.mb.menu -relief raised\
      -text $find_field
   
   menu .find.field.mb.menu
   .find.field.mb.menu add radiobutton -label All -variable find_field -value All 
   foreach i $allfields {
      .find.field.mb.menu add radiobutton -label $i -variable find_field -value $i
   }
   trace variable find_field w find_fieldchange_proc
   
   pack .find.field.l -side left
   pack .find.field.mb -fill x
   pack  .find.field -fill x
   
   ######################################################################
   # create a menu button for all reference types + All
   set find_reftype All
   frame .find.reftype
   label .find.reftype.l -text "Ref Type:" -width 12 -anchor e
   
   menubutton .find.reftype.mb -menu .find.reftype.mb.menu -relief raised -text $find_reftype
   menu .find.reftype.mb.menu
   .find.reftype.mb.menu add radiobutton -label All -variable find_reftype -value All
   foreach i $alltypes {
      .find.reftype.mb.menu add radiobutton -label $i -variable find_reftype -value $i
   }
   trace variable find_reftype w find_reftypechange_proc
   pack .find.reftype.l -side left -fill x
   pack .find.reftype.mb -fill x -expand 1
   pack .find.reftype -fill x -expand 1
   
   
   ######################################################################
   frame .find.years
   label .find.years.l -text "Years:" -width 12 -anchor e
   pack .find.years.l -side left
   entry .find.years.start -textvariable find_startyear 
   entry .find.years.end -textvariable find_endyear
   pack .find.years.l .find.years.start .find.years.end -side left -fill x -expand 1
   pack .find.years  -expand 1
   
   ######################################################################
   # the search list box
   frame .find.list
   listbox .find.list.lb -yscrollcommand ".find.list.sb set" -selectmode extended
   scrollbar .find.list.sb -command ".find.list.lb yview"
   pack .find.list.sb -side right -fill y
   pack .find.list.lb -side left -fill x -expand 1
   pack .find.list -fill x -expand 1
   
   bind .find.list.lb <Double-Button-1> { browse [selection_get -first] -focus}
   bind .find.list.lb <Return> {browse [selection_get -first] -focus}

   # next/prev buttons.  Get current selection index and incr/decr.
   bind .find <Down> {browseitem next .find.list.lb}
   bind .find <Up> {browseitem previous .find.list.lb}
   bind .find <Control-a> {allitems .find.list.lb}
   
   ######################################################################
 #  frame .find.search
   button .find.search -text "Search" -command searchbib
   pack .find.search  -side left -expand 1 -fill x
  # pack .find.search -expand 1 -fill x

   # message box
   message .find.m -justify left  -width 5c
   pack .find.m -side left -fill x -expand 1
   
   # the quit button
   button .find.help -text "Help" -command {briefhelp Find}
   button .find.dismiss -text "Dismiss" -command {destroy .find}
   pack .find.dismiss .find.help -side right -anchor e -fill x
}


# whenever find_field changes, relabel the menu button
proc find_fieldchange_proc {name el op} {
   global find_field
   
   .find.field.mb config -text $find_field
}

# whenever find_reftype changes, relabel the menu button
proc find_reftypechange_proc {name el op} {
   global find_reftype
   
   .find.reftype.mb config -text $find_reftype
}


#----------------------- MAIN WINDOW -------------------------------------

#---------- File menu -------------------

# save to a new file 
proc saveasbib {} {
   global fname  
   set fname [tk_getSaveFile -defaultextension .bib]
   if {$fname == ""} return
   testoutput 1 "saveasbib to $fname"
   savebib
}

# save selected entries
proc save_selected {} {
   global fname
   set selected_records [selection_get]
   if {$selected_records == ""} {return}
   set old_fname $fname
   set fname [tk_getSaveFile -defaultextension .bib]
   testoutput 1 "save <$selected_records> to $fname"
   savebib $selected_records
   set fname $old_fname
   wm title . [file tail $fname]
}

# save bibliografy, if args != "": save only these selected records
proc savebib {args} {
   global fname bibchanged citelist backup_max
   
   testoutput 1 "savebib to $fname"
   
   if {($fname == "") || ($fname == "<noname>")} {
      saveasbib
      return ;# otherwise we would have an infinite recursion
   }
   
   if {[file exists $fname] && $backup_max != 0} {
      # we don't want to overwrite an existing file, make a backup 
      # as does bibcard to a file named bibfile.bib.~VERSION~
      # on *DOS call the backup *.bi~
      # if $backup_max > 0, make not more than $backup_max backups

      set s {}
      # find all existing backups
      catch {set s [glob $fname.~*]}
      
      # find the highest to date
      set max 0
      foreach i $s {
         regexp {([1-9]+)~} $i matchall vers
         if {$vers > $max} {
            set max $vers
         }
      }
      # ours is the next one in sequence
      incr max
      # if backup_max > 0, make not more than $backup_max backups
      if {$backup_max && $max > $backup_max} {
         # rotate: discard oldest backup
	 set max 1
	 while {$max < $backup_max} {
 	    set prev $max
	    incr max
	    puts $max
	    catch {file rename -force $fname.~$max~ $fname.~$prev~}
         }
      } 	 
      puts $max
      # rename the bibliography file to the backup name
      # give a second try if we are an a 8.3 file system (DOS)
      if [catch {file rename -force $fname $fname.~$max~} info] {
      testoutput 3 "catch returns <$info>"
      file rename -force $fname "[file rootname $fname].bi~"
      }
   }
   # write the new data
   if {$args != ""} {
      eval writebib $args $fname; # eval: otherwise $args is just one word
   } else {
      writebib $citelist $fname
   }
   set bibchanged 0
}

# fetch the selected items: if args == -first -> just the first selection
proc selection_get {args} {

   set owner [selection own]
   if {($owner != ".refs.list") && ($owner != ".find.list.lb")} {
	tk_dialog .d {Error} "Selection must be in main reference or find list window" {} -1 OK
   	return "";
   }
   set stat [catch {selection get} str]
   if {$stat > 0} {
      tk_dialog .d {No selection} {No bibliography item was selected} {} 0 OK
      set str ""
   }
      # test, whether we want only one item
   if { [lindex $args 0]  == "-first"} {
      set str [lindex $str 0]
   }    
   return $str
}

proc quit {} {
   check_save
   
   exit
}

proc check_save {} {
   global bibchanged fname debug curkey
   
   if {$bibchanged > 0} {
      set r [tk_dialog .save {Bibliography modified} \
      "Bibliography $fname has been modified since last time it was saved.  
      Do you want to save it before exiting the application?" \
      warning 0 {Save File} {Discard Changes}]
      if {$debug} {
         puts "check_save returns $r"
      }
      switch $r {
         0	{savebib}
         1	{return}
      }
   }
}


proc openbib {} {
   global fname
   
   # first close the current bib
   closebib
   
   set types {
      {{Bib Files}       {.bib}        }
      {{All Files}        *             }
   }
   set fname [tk_getOpenFile -filetypes $types]
   
   if {$fname != ""} {
      # Open the file ...
      bibparse $fname
  
      wm title . [file tail $fname]
   }
}

proc mergebib {} {
   global fname
   
   set types {
      {{Bib Files}       {.bib}        }
      {{All Files}        *             }
   }
   set fname [tk_getOpenFile -filetypes $types]
   
   if {$fname != ""} {
      # Open the file ...
      bibparse $fname
   }
}

proc closebib {} {
   
   global REFLIST citelist fname bibchanged
   
   # if the current bib has changed, ask whether write it to disk
   check_save
   
   # clear the internal database
   if {[info exists REFLIST]} {
      unset REFLIST
   }
   set citelist {}
   .refs.list delete 0 end
   set fname "<noname>"
   set bibchanged 0
   
   wm title . " "
   
   #  close the browse box
   if {[winfo exists .browse]} {
      destroy .browse
   }
   
}

#---------- Edit menu -------------------

#GM, 30.1. a new function edit_item with subfunctions for 
# new, duplicate, delete, rename, crossref
proc edit_item {what} {
   global citelist REFLIST bibchanged reftype_default delete_confirm
   
   if {$what != "delete"} {
      if {$what != "new"} {
	 # not new or delete, is duplicate, rename, crossref
         # get the citekey for current entry
         set oldcitekey [selection_get -first]
         if {$oldcitekey == ""} {return}
      }
      # prompt for new cite key
      set newcitekey [getnewcitekey]
      if {$newcitekey == ""} {return}
   } else {
      # for deletion: get the citekey for all selected entries
      set oldcitekey [selection_get]
      if {$delete_confirm} {
         if [tk_dialog .d {Warning} "Delete:\n$oldcitekey?" {} 0 "Yes" "No"] {
            return
         }
      }
      destroy .browse      
   }
   
   if {$what == "new"} {
      # set to default reftype
      set REFLIST($newcitekey,reftype) $reftype_default
   }

   if {$what == "crossref"} {
         set REFLIST($newcitekey,reftype) $REFLIST($oldcitekey,reftype)
         set REFLIST($newcitekey,crossref) $oldcitekey
   }
   
   if {$what == "duplicate" || $what == "rename"} {
      # copy fields from old to new
      testoutput 1 "copying $oldcitekey to $newcitekey"
      foreach el [array names REFLIST $oldcitekey,*] {
         regexp {,([a-z]+)} $el matchall fieldname
         testoutput 2 "<$fieldname> = <$REFLIST($oldcitekey,$fieldname)>"
         set REFLIST($newcitekey,$fieldname) $REFLIST($oldcitekey,$fieldname)
      }
   }
   
   if {$what == "rename" || $what == "delete"} {
      foreach ditem $oldcitekey {
         testoutput 1 "deleting item $ditem"
         # unset the old array elements
         foreach el [array names REFLIST $oldcitekey,*] {
            regexp {,([a-z]+)} $el matchall fieldname
            unset REFLIST($oldcitekey,$fieldname)
         }
         # now take them out of the citelist 
         set i [lsearch -exact $citelist $ditem]
         set citelist [lreplace $citelist $i $i]
         # update the listbox in the main window
         update_citelistbox
      }
   }
   # note that we've updated the bib
   incr bibchanged

   if {$what != "delete"} {
      append_to_citelist $newcitekey
      .refs.list selection clear 0 end
      .refs.list selection set end
      browse $newcitekey -focus
   }
} 
# end of edit_item {what}

# push the currently selected bib entry to LyX
proc pushitem {} {
        global REFLIST citelist bibchanged cite_grouping

        # get the citekey for current entry
        set items [selection_get]
        if {$items == ""} {
                tk_dialog .d {No selection} {No bibliography item was selected} {} -1 OK
                return
        }

	if {$cite_grouping} {
		LyX_insertcite [join $items ,]
	} else {
		foreach item $items {
			LyX_insertcite $item
		}
	}
}

# navigate, show (which = first|previous|next|last) item in browse box
proc browseitem {which widget} {
   set curline [$widget curselection]
   set lastline [expr [$widget index end] -1]
   # clear all selections (may be more than one)
   $widget selection clear 0 end
   # deal with 0 or multiple
   if {[llength $curline] == 0} {set curline 0}
   if {[llength $curline] > 1} {set curline [lindex $curline 0]}
   switch $which {
      first {set curline 0}
      previous {if {$curline > 0} {incr curline -1}}
      next {if {$curline < $lastline} {incr curline}}
      last {set curline $lastline}
   }
   $widget selection set $curline
   $widget see $curline
   browse [selection_get]
}

# select all items
proc allitems {widget} {
   $widget selection set 0 end
}

# bring up the find/search window which then does its own thing
proc finditem {} {
   # create search window if need be
   if {[winfo exists .find] == 0} {
      create_find
   }
   focus .find.str.e
}

# selection handler for PRIMARY requests
#
#  assume the string is in writebib_str, return the amount requested in
# the selection request.
proc selection_handler {offs maxb} {
   global	writebib_str debug
   
   if {$debug} {
      puts "selection_hander invoked: $offs $maxb"
   }
   set s [string range $writebib_str $offs [expr $offs+$maxb-1]]
   #puts "s: $s"
   return $s
}

proc selection_lost {} {
   #puts "selection lost"
}


proc copyitem_to_paste {} {
   # format the item into a string
   set cl [selection_get]
   writebib2str $cl
   # put the string to the PRIMARY selection 
   #   grab the PRIMARY selection
   selection own -command selection_lost -selection PRIMARY .
   #   create a handler for PRIMARY selection requests
   selection handle -selection PRIMARY -type STRING . selection_handler
}

# paste the current paste buffer into the bib
proc pasteitem {} {
	global bibchanged

        # get the paste buffer
        set s [selection get -selection PRIMARY]

        # parse it
        if {[catch {set dup [bibparse_s $s]}] != 0} {
                tk_dialog .d {Error} "Syntax error with pasted data\nPerhaps not BibTeX data?\nIgnoring it." {} -1 OK
	} else {
		# put it in the bib
		set REFLIST_update 0
		update_citelistbox
		puts "$dup duplicates loaded"

		incr bibchanged
	}
}

proc not_implemented {func} {
   tk_dialog .d {Unimplemented} "Feature $func is not yet implmented" {} -1 OK
}

# prompt for a new cite key
proc getnewcitekey {} {
   global citelist newcitekey
   set answer 1;  # tkdialog returns 1 for "Retry"

   # popup a box and get the new cite key
   toplevel .newcitekey
   label .newcitekey.l -text "New cite key:"
   entry .newcitekey.e 
   pack .newcitekey.l .newcitekey.e -side left
   
   # grab focus
   focus .newcitekey.e
   
   # wait for <Return> at end of line
   bind .newcitekey <Return> {set newcitekey [.newcitekey.e get]}
   
   while {$answer } {
      tkwait variable newcitekey
      # check if it exists, if so: browse it and give a warning
      if {[lsearch $citelist $newcitekey] < 0} {
         break
      } else {   
         testoutput 1 "citekey exists"
         set answer [tk_dialog .d {Warning} \
           "cite key already exists" {} 1 "Abort" "Retry" "Browse"]
         testoutput 3 "tkdialog returns $answer"
         if {$answer == 0} {set newcitekey ""}
         if {$answer == 2} {browse $newcitekey; set newcitekey ""; break}
      }
   }
   # clean up
   destroy .newcitekey
   
   return $newcitekey
}

# put into a message window, so we can compare two entries or
# copy and paste stuff to a different entry, in the long run the possibility 
# to have two browse windows might be better
proc displayitem {} {

   global REFLIST citelist
   
   # format entry for display
   set citekey [selection_get]
   append itemstring  "$REFLIST($citekey,reftype): $citekey\n"
   foreach i [array names REFLIST $citekey,*] {
      if {$REFLIST($i) != ""} {
         set j [string first "," $i]
         incr j
         append itemstring "[string range $i $j end] = $REFLIST($i)\n"
      }
   }
   # set up a window
   toplevel .displayitem
         frame .displayitem.f
      text .displayitem.f.t -width 80 -height 30 -wrap word \
        -yscrollcommand ".displayitem.f.scroll set" 
      scrollbar .displayitem.f.scroll -command ".displayitem.f.t yview"
      button .displayitem.b -text "OK" -command "destroy .displayitem"
      pack .displayitem.f.t -side left -fill x -expand 1
      pack .displayitem.f.scroll -side right -fill y -expand 1
      pack .displayitem.f
      pack .displayitem.b -side bottom  -anchor s 
      
      bind .displayitem q {destroy .displayitem}
      bind .displayitem <Return> {destroy .displayitem}
   wm title .displayitem "Show item"
   # insert itemtext
      
   .displayitem.f.t configure -state normal
   .displayitem.f.t delete 0.0 end 
   .displayitem.f.t insert end $itemstring
   .displayitem.f.t configure -state disabled

}

# for diagnostics, list current fields to stdout (bound to key 's')
proc showitem {} {
   global REFLIST citelist
   
   puts  ""
   set oldcitekey [selection_get]
   foreach i [array names REFLIST $oldcitekey,*] {
      if {$REFLIST($i) != ""} {
         puts stdout "($i) = $REFLIST($i)"
      }
   }
}

proc sortitems {} {
   global	citelist
   
   set citelist [lsort $citelist]
   
   update_citelistbox
}

# 18/5/2000 John Fulton <John.Fulton@iname.com>
proc printitem {} {
# memory of last print command entered
	global global_print_cmd


        # local print command
        set printcmd ""

        # popup a box and get a different print command
        toplevel .printcmd
        label .printcmd.l -text "Print command:"
        entry .printcmd.e -textvariable global_print_cmd
	
	button .printcmd.print -text "Print" -command {
		# get the item to print
		set s [selection get -selection PRIMARY]
		puts $s

		# print the entry
		writebib $s $global_print_cmd

		# clean up
		destroy .printcmd
	}
	button .printcmd.cancel -text "Cancel" -command {
		# clean up
		destroy .printcmd
	}
        pack .printcmd.l  -side left
        pack .printcmd.e -side left
        pack .printcmd.print  -ipadx 2 -side left
        pack .printcmd.cancel  -side left

        # grab focus
        set oldFocus [focus]
        focus .printcmd.e

        # wait for <Return> at end of line
        tkwait window .printcmd
        focus $oldFocus
}


#---------- Help menu -------------------
proc abouttkbibtex {} {
   global release
   toplevel .about
   
   set aboutstr "tkbibtex
   
   A portable browser/editor for BibTeX format bibliographies.
   
   by Peter Corke 1/97              (pic@cat.csiro.au)
   major modifications by G. Milde  (g.milde@physik.tu-dresden.de)
   Release $release"
   message .about.m  -width 40c -text $aboutstr
   
   button .about.www -text "Goto home page" -command {
      exec netscape -remote openURL(http://www.cat.csiro.au/dmt/programs/autom/pic/tkbibtex.html)
   }
   
   button .about.b -text "OK" -command "destroy .about"
   pack .about.m .about.www .about.b
   wm title .about "About tkbibtex"
}

proc briefhelp {topic} {
   global usage
   
   set helptopics {Usage Keys Menus Browse Find}
   
   set helpstr(Usage) $usage
   
   set helpstr(Keys) \
"Key bindings in main window:

 Selection:
   <Mouseclick>        select entry
   <Shift-Mouseclick>  select a block of entries
   <Crtl-Mouseclick>   select multiple entries
   <Ctrl-A>            Select all Items
   
  On the selected entry: 
   <Enter>             Browse entry (show in browse window for editing)
   <DoubleMouseclick>  Browse entry
   <Up>                Browse next entry
   <Down>              Browse previous entry
   
   u                   Duplicate entry           (Edit|Duplicate-entry)
   s                   Show entry (no editing)
   c                   Push citation to LyX
   <Del>               Delete entry              (Edit|Delete)
   ^C                  Copy item to paste buffer (Edit|Copy)
   ^V                  Paste from buffer         (Edit|Paste)
   
  Misc.:
   f                   Find entry                (Edit|Find)
   n                   Create new bib entry      (Edit|New-entry)
   q                   Quit
   
Keybindings in Browse window:

   <Tab> or  <Down>    Next field
   <Enter>             Next field (in one-line fields)
   <Shift Tab> or <Up> Previous field
   <Alt> + Underlined  invoces Menus and Buttons"
   
   
   set helpstr(Menus) "Tkbibtex Menus
   
File menu:
   Open           Open a file via browser window
   Merge          Merge a file via browser window (records with same
                  Citekey will overwrite those already loaded)
   SaveAs...      Save data to a different file 
   Save           Save data
   Save Selected  Save selected entries
   Close          Close the file (save if needed)
   Exit           Exit program (save if needed)
   
   for Close and Exit a prompt box will be issued if the bibliography
   has been modified but not yet saved.  When the file is written the
   previous version is saved with a unique appended number.
   
Edit menu:
   New entry        Create a new BibTeX entry
   Duplicate entry  Duplicate the current selection but assign new citekey
   Crossref entry   Create a new citation with cross reference to the current selection
   Find entry       Invoke the search window
   Delete entry     Delete the selected entries from the database
   Copy to buffer   Copy selected entries to PRIMARY cut buffer, can be
                    pasted into other applications.
   Insert to LyX    Push citation to Lyx
   Show entry       Show entry in a message window (no editing)
   Sort             Sort keys alphabetically
   Print            Print bib items"
   
   set helpstr(Find) "Search/find window:

   * Find all entries containing the searchstring in specified field
   * Seachstring is a regular expression: .*?()[]\ have special meanings
   * Either start year or end year or both may be specified.
   * The entries found are displayed in a list which can be browsed by the
     same key bindings as in the main window:

     Selection:
      <Mouseclick>         select entry
      <Shift-Mouseclick>   select a block of entries
      <Crtl-Mouseclick>    select multiple entries
      <Ctrl-A>             Select all Items
      
     On the selected entry: 
      <Enter>              Browse entry (show in browse window for editing)
      <Double-Mouseclick>  Browse entry
      <Up>                 Browse next entry
      <Down>               Browse previous entry"
     
     
   set helpstr(Browse) "Browse box:

* The browse box shows all fields for the specified entry, 
  allowing for editing

      !  BibTeX distinguishes between 
         - normal fieldtext (enclosed in brackets or double quotes), 
         - numbers (may be enclosed or not) and 
         - strings (words beginning with a character, not enclosed).
         
      -> Normal text entries will become enclosed in brackets.
      -> If an entry shall be written to the file as is, precede it with 
         a hash (e.g. month strings -> #jan - #dec).
         
* The reftype button brings up a menu of reference types to choose from

* Black lines seperate the three different types of field BibTeX knows
  about: 
     Required fields   (have to be present to get a well formed citation)
     Optional fields   (not necessary but show up in the citation if present)
     Additional fields (ignored by the standard BibTeX styles
                        but may contain usefull information)               

* Some fields are foldable multiple line entries that unfold if the label
  button is clicked on.
  
* Right clicking in an entry box brings up either:
	* a menu of standard monthnames (if a month entry)
	* jump to the citation that is cross-referenced (if a crossref entry)
	* a menu of string items (if there are any defined) which will 
	  be inserted.

* Keybindings:
   <Tab> or  <Down>     Next field
   <Enter>              Next field (in one-line fields)
   <Shift Tab> or <Up>  Previous field
   <Alt> + Underlined   invoces Buttons"
   
   
   # set up the help window
   # (show help in a text widget, so we can incorporate hypertext tags later)
   if {![winfo exists .briefhelp]} {
      toplevel .briefhelp
      
      frame .briefhelp.m 
      label .briefhelp.m.l -text "Topics:"
      pack .briefhelp.m 
      pack .briefhelp.m.l -side left
      foreach top $helptopics {
         button .briefhelp.m.[string tolower $top] -text $top -underline 0 \
           -command "briefhelp $top"
         pack .briefhelp.m.[string tolower $top] -side left
         
         bind .briefhelp <Alt-Key-[string index [string tolower $top] 0]> \
           "briefhelp $top; break"
      }
      #.briefhelp configure -menu .briefhelp.m does not work as desired
      
      
      frame .briefhelp.f
      text .briefhelp.f.t -width 80 -height 20 \
        -yscrollcommand ".briefhelp.f.scroll set" 
      scrollbar .briefhelp.f.scroll -command ".briefhelp.f.t yview"
      button .briefhelp.b -text "OK" -command "destroy .briefhelp"
      pack .briefhelp.f.t -side left -fill x -expand 1
      pack .briefhelp.f.scroll -side right -fill y -expand 1
      pack .briefhelp.f
      pack .briefhelp.b -side bottom  -anchor s 
      
      bind .briefhelp q {destroy .briefhelp}
      bind .briefhelp <Escape> {destroy .briefhelp}
      wm title .briefhelp "Tkbibtex Help"
   } else {
      foreach top $helptopics {
         .briefhelp.m.[string tolower $top] configure -state normal
      }
   }
   # make the topics button active
   .briefhelp.m.[string tolower $topic] configure -state active 

   # insert the topic
   
   .briefhelp.f.t configure -state normal
   .briefhelp.f.t delete 0.0 end 
   .briefhelp.f.t insert end $helpstr($topic)
   .briefhelp.f.t configure -state disabled

}

# handle changes to iconify/deiconify state, make all windows adopt the same
# state.
proc wm_statechange {w} {
	global	window_state

	# check if window state has changed
	set toplevel [winfo toplevel $w]
	if {[wm state $toplevel] != $window_state} {
		#puts "window state changed $window_state"
		set window_state [wm state .]
		if {[wm state $toplevel] == "normal"} {
			# unminimize all windows
			wm deiconify .
			if {[winfo exists .find]} {
				wm deiconify .find
			}
			if {[winfo exists .browse]} {
				wm deiconify .browse
			}
		} elseif {[wm state $toplevel] == "iconic"} {
			# minimize all windows
			wm iconify .
			if {[winfo exists .find]} {
				wm iconify .find
			}
			if {[winfo exists .browse]} {
				wm iconify .browse
			}
		}
	}
}
#---------- create the main window ------------------
proc create_main {} {
   global alltypes refs_height refs_width
   
   
#   # create the menu bar
   menu .mbar -tearoff 0
   .mbar add cascade -label "File" -menu .mbar.file -underline 0
   .mbar add cascade -label "Edit" -menu .mbar.edit -underline 0
   .mbar add cascade -label "Help" -menu .mbar.help -underline 0

# declare the menu to the main window
   . configure -menu .mbar

   # create the File menu
   menu .mbar.file
#   .mbar.file add command -label "New" -underline 0 -command closebib
#   this might beocme usefull if we can open multiple files...
   .mbar.file add command -label "Open" -underline 0 \
        -accelerator F3 -command openbib
   .mbar.file add command -label "Merge" -underline 0 -command mergebib
   .mbar.file add command -label "SaveAs" -underline 4 \
    	-accelerator Shift-F2 -command saveasbib
   .mbar.file add command -label "Save" -underline 0 \
    	-accelerator "^S / F2" -command savebib
   .mbar.file add command -label "Save Selected" -underline 7 \
      -command {save_selected}
   .mbar.file add command -label "Print Selected ..." -underline 0 \
       -accelerator P -command printitem
   .mbar.file add command -label "Close" -underline 0 \
    	-accelerator Shift-F3 -command closebib
   .mbar.file add command -label "Exit" -underline 0 \
    	-accelerator ^Q -command quit
   
   # create the edit menu
   menu .mbar.edit
   .mbar.edit add command -label "New entry" -underline 0 \
       -accelerator N -command {edit_item new}
   .mbar.edit add command -label "Duplicate entry" -underline 1 \
       -accelerator U -command {edit_item duplicate}
   .mbar.edit add command -label "Cross-reference entry" \
       -accelerator X -command {edit_item crossref}
   .mbar.edit add command -label "Find entry ..." -underline 0 \
       -accelerator F -command finditem
   .mbar.edit add command -label "Rename entry" -underline 0 \
       -accelerator R -command {edit_item rename}
   .mbar.edit add command -label "Delete entry" -underline 0 \
       -accelerator <Del> -command {edit_item delete}
   .mbar.edit add command -label "Push to LyX" -underline 0 \
       -accelerator c -command pushitem
   .mbar.edit add command -label "Copy to buffer" -underline 0 \
       -accelerator ^C -command copyitem_to_paste
   .mbar.edit add command -label "Paste buffer" -underline 0 \
       -accelerator ^V -command pasteitem
   # for diagnostics, list current fields 
   .mbar.edit add command -label "Show entry" -underline 0 \
       -accelerator S -command displayitem
   .mbar.edit add command -label "Sort" -underline 1 -command sortitems
   
   # create the help menu
   menu .mbar.help
   .mbar.help add command -label "Brief help" -underline 0 \
       -accelerator <F1> -command {briefhelp Keys}
   .mbar.help add command -label "About tkbibtex" -underline 0 \
       -command abouttkbibtex
   
   menubutton .new -relief raised -text "New" -menu .new.menu
   menu .mbar.edit.new
   foreach i $alltypes {
      .mbar.edit.new add command -label $i  -command "new_item $i"
   }
   
   # now the message window
   message .m -relief groove -width 30c -justify  left -anchor w
   pack .m -fill x -expand 1
   
   # then the scrolling list of citations
   frame .refs
   listbox .refs.list -height $refs_height -width $refs_width\
      -yscrollcommand ".refs.scroll set" -selectmode extended
   scrollbar .refs.scroll -command ".refs.list yview"
   
   pack .refs.list -side left -fill x -fill both -expand true 
   pack .refs.scroll -side right -fill y 
   pack .refs -side bottom -expand true -fill both
   
   # double click on the cite key to display it in browse box
   bind .refs.list <Double-Button-1> {browse [selection_get -first] -focus}
   bind . <Return> {browse [selection_get -first] -focus}
   bind . <Down> {browseitem next .refs.list}
   bind . <Up> {browseitem previous .refs.list}
   
   # some helpful keyboard bindings
   bind Button <Key-Return> "tkButtonInvoke %W"; # Enter invokes Buttons
   bind . c {pushitem}
   bind . u {edit_item duplicate}
   bind . f {finditem}
   bind . <Alt-f> { }; # dummy entry to enable Menu shortcut
   bind . n {edit_item new}
   bind . p {printitem}
   bind . <Control-q> {quit}
   bind . q {quit}
   bind . r {edit_item rename}
   bind . s {displayitem}
   bind . <Control-c> copyitem_to_paste
#   bind . <Control-Key-Insert> copyitem_to_paste
# this binding does prevent copyitem_to_paste from working! (Why?)
   bind . <Control-v> pasteitem
#   bind . <Shift-Key-Insert> pasteitem
# this binding does prevent pasteitem from working! (Why?)
   bind . <Control-a> {allitems .refs.list}
   bind . <Delete> {edit_item delete}
   bind . <Unmap> {wm_statechange %W}
   bind . <Map> {wm_statechange %W}
   wm protocol . WM_DELETE_WINDOW quit
   wm protocol . WM_SAVE_YOURSELF quit
}

# show one line status messages in the main window
proc showmsg {m} {
   global interactive_mode

   if {$interactive_mode} {
	   .m config -text $m
	   update idletasks
   }
}

#---------------------- LyX support -----------------------

# Interface to Lyx based on development/LyXserver/sampleclient.tcl
# =========================================================================
#   File: sampleclient.tcl, chb, Sun 05.11.1995 (19:24)
#   sampleclient.tcl,v 1.1.1.1 1996/08/19 14:39:38 larsbj Exp
#   This file contains examples for communicating to LyX via the
#   LyXserver interface. It contains a panel of shortcuts to
#   demonstrate how users can define their own macros. It also shows
#   how new commands can be built into LyX using the 'notify' mechanism.
# =========================================================================


# --- 1. check cmdargs (pipename) -----------------------------------------

set LyXChan -1

proc LyX_connect {} {
   global LyXpipe LyXChan
   
   set inpipe  $LyXpipe.in
   
   if { [file exists $inpipe] } {
      if { "[file type $inpipe]" != "fifo" }  {
	 tk_dialog .d {LyX connection} "LyXpipe <$inpipe> is not a pipe!" {} -1 OK
      }
      puts "Connecting to LyX via $LyXpipe.in"
      set LyXChan [open $inpipe {WRONLY NONBLOCK}]
puts "<LyxChan $LyXChan>"
   } else {
	 tk_dialog .d {LyX connection} "No LyXpipe ($LyXpipe.*) exists\nCheck your .LyXrc file" {} -1 OK
   }
   
}

# ---
#  Format for communication:
#
#    client->LyX:          "LYXCMD:<client>:<command>:<argument>" >$inpipe
#    LyX->client (answer): "INFO:<client>:<command>:<data>"       <$outpipe
#    LyX->client (notify): "NOTIFY:<key-sequence>"                <$outpipe
#    (notifies are asynchroneous and are handled by 'outputhandler'
#     above)
# ---

proc LyX_insertcite {cite} {
   global LyXChan
   
   # open the pipe each time, in case LyX crashes...
   LyX_connect
   puts "sending citation $cite to LyX"
   puts $LyXChan "LYXCMD:sampleclient:citation-insert:$cite"
   close $LyXChan
}

#---------------------- Auxilliary functions -----------------------------

# Put a text on stdout, if the global var debug is >= debug_level
proc testoutput {debug_level text} {
   global debug
   if {$debug >= $debug_level} {puts stdout $text}
} 

proc show_usage {} {
   global	usage
   puts stdout $usage
   exit
}


#------------------------------ MAIN BODY ----------------------------

#warn about wrong version
if {[info tclversion] < 8} {
   puts stdout "tkbibtex needs Tcl/Tk version 8.0 or later"
}

# handle command line switches
while {[llength $argv] > 0} {
   if {$debug} {
      puts [lindex $argv 0]
   }
   switch -regexp -- [lindex $argv 0] {
      ^-debug     {	set debug [lindex $argv 1]; \
           set argv [lrange $argv 2 end] ; \
        }
      ^-ys     {	set arg_ys [lindex $argv 1]; \
           set argv [lrange $argv 2 end]; \
           incr command_line_mode
      }
      ^-ye     {	set arg_ye [lindex $argv 1]; \
           set argv [lrange $argv 2 end]; \
           incr command_line_mode
      }
      ^-last   {	set t [clock seconds]; \
           set arg_ye [clock format $t -format %Y]; \
           set arg_ys [expr $arg_ye-[lindex $argv 1]]; \
           set argv [lrange $argv 2 end]; \
           incr command_line_mode
      }
      ^-type   {	set arg_reftype [lindex $argv 1]; \
           set argv [lrange $argv 2 end]; \
           incr command_line_mode
      }
      ^-field  {	set arg_field [lindex $argv 1]; \
           set argv [lrange $argv 2 end]; \
           incr command_line_mode
      }
      ^-search  {	set arg_search [lindex $argv 1]; \
           set argv [lrange $argv 2 end]; \
           incr command_line_mode
      }
      ^-exact	-
      ^-case	{	set arg_ignorecase 0; \
           set argv [lrange $argv 1 end]; \
           incr command_line_mode
      }
      ^-count	{	set arg_count 1; \
           set argv [lrange $argv 1 end]; \
           incr command_line_mode
      }
      ^-l      -
      ^-list   {       set arg_list 1; \
                      set argv [lrange $argv 1 end]; \
                      incr command_line_mode
      }

      ^-lyx   {	set LyXpipe [lindex $argv 1]; \
                set argv [lrange $argv 2 end]; \
        }
      ^-help	-
      ^-.*	{	show_usage}
      default	{break}
   }
}


if {$command_line_mode} {
   # COMMAND LINE MODE, NO DISPLAY
   set interactive_mode false
   
   # read string file if it exists
   set strfname [find_on_path $strfile]
   if {$strfname != {}} {
      bibparse_f $strfname
   }

# load the specified bibtex files if they exist
   foreach f $argv {
      set fp [find_on_path $f]
      if {$fp != {}} {
         bibparse_f $fp
      }
   }
   
   set found [do_search $arg_search $arg_reftype $arg_field $arg_ys \
     $arg_ye $arg_ignorecase]
   if {$arg_count} {
      puts stdout [llength $found]
   } else {
      puts stdout  [writebib2str $found]
   }
   exit 0
} else {
   # INTERACTIVE MODE
   
   set interactive_mode true
   # create the main window
   create_main
   
   update idletasks
   
   # read string file if it exists
   set strfname [find_on_path $strfile]
   if {$strfname != {}} {
      bibparse $strfname
   }
   
   # load the specified bibtex files if they exist
   foreach f $argv {
      set fname $f
      set fp [find_on_path $f]
      if {$fp != {}} {
         bibparse_f $fp
      }
      update_citelistbox
   }
   
   # unset global filename if more than one input file
   if {[llength $argv] >  1} {
      set fname "<noname>"
   }

   wm title . $fname
  
   showmsg ""
}