[go: up one dir, main page]

Menu

[80c337]: / lob.h  Maximize  Restore  History

Download this file

2669 lines (2479 with data), 125.9 kB

   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
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
#ifndef LOB
#define LOB
#include <OmHeaders.h>
#include <QObject>
#include <QVariant>
#include <QFile>
#include <QStringList>
#include <QMap>
#include "laddress.h"
#include "safesingleton.h"
class LobChange;
/** \brief Lob is short for Lurch Object, a tuning of OpenMath objects for
* Qt, Lurch, and scripting
*
* <h2>Purpose</h2>
* This class is a wrapper for an OpenMath object; it differs from OpenMath
* objects in three ways, matching this class's three purposes.
* <ol>
* <li>This class uses Qt data types (like QString, QFile, etc.) where the OpenMath C++
* library underlying it uses standard types (C FILE*, std list, etc.). Thus this
* class integrates OpenMath into a Qt environment more smoothly.</li>
* <li>This class contains some functions tailored to how Lurch makes use of OpenMath,
* corresponding to definitions such as Lurch Object, Lurch Reference, Lurch Script,
* and Lurch Document.</li>
* <li>This class uses properties and public slots to expose to scripting environments
* just those members that should be script-accessible.</li>
* </ol>
* A more fine-grained breakdown of the above three purposes appears in a few paragraphs.
*
* \anchor LobMemoryManagement
* <h2>Memory management</h2>
* Creating a Lob wrapper for an OmNode* introduces the tree rooted at that OmNode* to the
* Lob memory management system, which takes ownership of the OmNode and all its children,
* and will delete them later, when no Lob refers to them or to any other OmNode in the
* same tree. Creating a Lob wrapper for an OmNode* therefore gives ownership to the Lob
* (and to the rest of the Lobs, as a collective) and you should not subsequently delete the
* OmNode*, nor any other node in the same tree, because Lobs can navigate to other nodes in
* the same tree using methods like parent() and nextSibling() and so on.
* If you wish to maintain ownership, create a Lob
* wrapper for an OmNode::clone() of the desired OmNode* instead.
*
* It is not necessary for clients to learn the details of the Lob memory management system.
* You are free to create and destroy Lobs as you see fit without worrying about cleaning
* up their contents. You are also free to assign one Lob to another or create a copy()
* as you need to, and the Lob class will handle cleaning up any
* OmNodes created in such a process, provided that you ensure the Lobs themselves are
* deleted. The class is designed to be used without pointers; that is, you typically
* declare variables of type Lob, not type Lob*. If you are curious about the details of
* the Lob memory management system anyway, see hold() and release().
*
* For instance, here is an example of typical, intended C++ use of Lobs. Analogous code is
* acceptable in scripts.
* \code
* Lob myLob = Lob::fromXML( "<OMI>5</OMI><OMV name=\"someVariable\"/>" );
* int x = myLob.numChildren(); // x is now == 2
* myLob = myLob.child().nextSibling();
* QVariant v = myLob.toVariant(); // v is now the QVariant string "someVariable"
* \endcode
* At no point in this code is any of the OmNode tree deleted, because myLob still points
* to part of it. When myLob goes out of scope, the whole tree will be deleted.
*
* <h2>Categories of functionality</h2>
* The three purposes of this class, as stated above, break down into the following more
* specific categories of functionality which
* roughly partition this class's members, with links to the corresponding properties
* and functions in each category.
* <ul>
* <li><b>Reading and writing OM trees:</b>
* Create OpenMath trees from QStrings or QFiles, and write representations of them
* into QStrings or QFiles with the four routines
* fromXML(QString), fromXML(QFile&), toString(), and save().</li>
* <li><b>Navigating OM trees:</b>
* The underlying OpenMath tree structure is accessible through this class's methods,
* specifically numChildren(), child(), parent(), nextSibling(), previousSibling(),
* etc. Although code like
* <code>myLob.child().nextSibling().nextSibling().getID()</code>
* creates many intermediate objects to do its work, all are created on the stack
* and will thus be automatically cleaned up in the same scope. Such code is
* well within the confines of the expected use of such functions, in C++ or in
* scripts.</li>
* <li><b>Modifying OM trees:</b>
* Use functions such as addChild(), insertChild(), removeChild(),
* setAttribute(), removeAttribute(), set(), and remove().</li>
* <li><b>Converting basic data types:</b>
* The properties basicType (accessed through isBasicType()) and basicValue (accessed
* through toVariant()) check whether this Lob points to
* an OpenMath object of a basic type, and if so, convert it to a suitable Qt type.
* A corresponding Lob::fromVariant(QVariant) method allows creation of OpenMath
* objects from Qt data.</li>
* <li><b>Attributes and comments:</b>
* Attributes can be read using the attribute() method.
* Comments can be read and written using the routines numComments(), comment(),
* comments(), setComments(), insertComment(), appendComment(), and removeComment().
* <li><b>Lurch references:</b>
* You can create an ID reference to a Lob with reference(), and dereference such a
* reference (obtaining the referent Lob) with referent(). You can get a Lob's
* nickname with getNickname() and read nickname references
* from Lurch Reference objects with getNicknameReference().</li>
* <li><b>Lurch Scripts:</b>
* You can check whether a Lob wraps a script using isScript(), and if it returns
* true, then get the corresponding parts of the script with scriptLanguage(),
* scriptCode(), and scriptType().</li>
* <li><b>Lurch documents:</b>
* The method isDocument() tells whether the wrapped node represents a Lurch Document,
* and if so, the methods getAuthor(), getTitle(), getVersion(), getURN(),
* and getDependencies() can be used on it.</li>
* </ul>
*
* This class is tested by methods in the class test_lob.
*/
class Lob : public QObject
{
Q_OBJECT
/** \brief Give scripts access to read the "empty" state (through isEmpty())
* \see isEmpty()
*/
Q_PROPERTY( bool empty READ isEmpty STORED false )
/** \brief Give scripts access to read whether this Lob is modifiable
*
* All routines that reference this are tested in test_lob_edit::test_read_only().
*
* \see isEditable(), setEditable()
*/
Q_PROPERTY( bool editable READ isEditable STORED false )
/** \brief Give scripts access to read the type of the wrapped node
* \see scriptNodeType()
*/
Q_PROPERTY( int type READ scriptNodeType STORED false )
/** \brief Give scripts access to convert a wrapped basic node to a QVariant
* \see toVariant()
*/
Q_PROPERTY( QVariant basicValue READ toVariant STORED false )
/** \brief Give scripts access to read the attribute keys of the wrapped node
* \see scriptAttributeKeys()
*/
Q_PROPERTY( QVariantList keys READ scriptAttributeKeys STORED false )
/** \brief Give scripts access to read the number of attribute keys of the wrapped node
*
* Script code like <code>myLob.numKeys</code> will give the same value as
* <code>myLob.keys.length</code>, but will be more efficient, because the whole
* keys array does not need to be created.
*
* \see numAttributes()
*/
Q_PROPERTY( uint numKeys READ numAttributes STORED false )
/** \brief Give scripts access to read the nickname attribute of a Lurch Object
* \see getNickname(), setNickname()
*/
Q_PROPERTY( QString nickname READ getNickname WRITE setNickname STORED false )
/** \brief Give scripts access to read the author field of a Lurch Document
* \see getAuthor(), setAuthor()
*/
Q_PROPERTY( QString author READ getAuthor WRITE setAuthor STORED false )
/** \brief Give scripts access to read the title field of a Lurch Document
* \see getTitle(), setTitle()
*/
Q_PROPERTY( QString title READ getTitle WRITE setTitle STORED false )
/** \brief Give scripts access to read the encoding language field of a Lurch Document
* \see getEncodingLanguage(), setEncodingLanguage()
*/
Q_PROPERTY( QString encoding READ getEncodingLanguage WRITE setEncodingLanguage
STORED false )
/** \brief Give scripts access to read the version field of a Lurch Document
* \see getVersion(), setVersion()
*/
Q_PROPERTY( QString version READ getVersion WRITE setVersion STORED false )
/** \brief Give scripts access to read the dependencies list of a Lurch Document
* \see getDependencies(), setDependencies()
*/
Q_PROPERTY( QStringList dependencies READ getDependencies WRITE setDependencies
STORED false )
/** \brief Give scripts access to read the URN of a Lurch Document
* \see getURN(), setURN()
*/
Q_PROPERTY( QString URN READ getURN WRITE setURN STORED false )
/** \brief Give scripts access to read the code of a Lurch Script
* \see scriptCode(), setScriptCode()
*/
Q_PROPERTY( QString code READ scriptCode WRITE setScriptCode STORED false )
/** \brief Give scripts access to read the scripting language of a Lurch Script
* \see scriptLanguage(), setScriptLanguage()
*/
Q_PROPERTY( QString language READ scriptLanguage
WRITE setScriptLanguage STORED false )
/** \brief Give scripts access to read the type of a Lurch Script
* \see scriptType(), setScriptType()
*/
Q_PROPERTY( QString scriptType READ scriptType
WRITE setScriptType STORED false )
/** \brief Give scripts access to read the nickname from a Lurch Reference
* \see getNicknameReference(), setNicknameReference()
*/
Q_PROPERTY( QString nicknameReference READ getNicknameReference
WRITE setNicknameReference STORED false )
/** \brief Give scripts access to this Lob's comments, as a single array
* \see comments()
*/
Q_PROPERTY( QStringList comments READ comments WRITE setComments STORED false )
public:
/** \brief Constructor that initializes this to point to the given OpenMath object
*
* \param wrapThis Defaults to no object, which makes this Lob "empty"
* (meaning it refers to nothing, and any calls to any methods herein
* will return undefined/useless information and/or not do anything).
* \param editable Initial value for the editable property
*
* This is tested by test_lob::test_basics().
*
* \see empty, editable
*/
Lob ( OmNode* wrapThis = 0, bool editable = true );
/** \brief Copy constructor, initializes this to wrap the same object as the given Lob
*
* Thus this creates a new Lob, but not a new OmNode tree. Only the wrapper is cloned.
* To create a full tree copy, see copy().
*
* You can safely copy Lobs in this way as much as you like without worrying about
* memory management issues; if you delete all your Lobs, all their wrapped OmNodes
* will also be deleted, none too soon or too late. See \ref LobMemoryManagement
* "the notes on memory management".
*
* This is tested by test_lob::test_copies().
*/
Lob ( const Lob& copyThis );
/** \brief Destroys the Lob, and possibly the wrapped node, if it is time to do so
*
* For information on the memory management system Lobs use to only delete wrapped
* OmNodes when it is time to do so, \ref LobMemoryManagement "see above". In general,
* an OmNode* is only deleted if no other Lob in existence wraps it or any other node
* in the same tree (including attribute nodes).
*/
~Lob ();
/** \brief Change this Lob to wrap the same OpenMath node as a different Lob
*
* It is safe to assign one Lob to another; no memory leaks can happen, because
* no new objects are created in the process. This assignment simply modifies this
* Lob to wrap the same OpenMath object as the parameter \a rhs.
*
* This is tested by test_lob::test_copies().
*/
Lob& operator= ( const Lob& rhs );
/** \brief Check whether two Lobs wrap the same OpenMath object
*
* Two Lobs are considered equal if they wrap the same OpenMath object.
* The reason for this is that the Lob is really just an OpenMath object in the
* first place, with convenience functions for our particular uses of OpenMath,
* Qt, scripting, etc. Thus the only data in a Lob is the OpenMath object, making two
* Lobs equal if and only if their wrapped objects are equal.
*
* This is tested by test_lob::test_copies().
*
* Script authors can access this with the <code>.equals()</code> member function
* of Lob objects in script.
*
* \see equivalentTo()
*/
friend bool operator== ( const Lob& a, const Lob& b );
/** \brief Simply the negation of the == operator for Lobs
*
* This is tested by test_lob::test_copies().
*
* \see operator==(), equivalentTo()
*/
friend bool operator!= ( const Lob& a, const Lob& b );
/** \brief This operator is not very useful practically, except for enabling hashing Lobs
*/
friend bool operator< ( const Lob& a, const Lob& b );
/** \brief Saves a representation of the node in OpenMath's XML encoding to the file
*
* Writes the OpenMath XML representation to the given file. The file is closed again
* at the end of this routine if and only if it was closed when the routine was called.
* The \a message parameter is used as in fromXML(QFile&).
* \return true on success, false for any type of failure
*
* This is tested by test_lob::test_qfile_qstring().
*
* \see fromXML(QFile&), toString()
*/
bool save ( QFile& out, QString* message = 0 );
/** \brief Assuming the wrapped OpenMath object has basic type, convert it to a QVariant
*
* If this object wraps an OpenMath object of a basic type, then it can be converted to
* a QVariant according to the following convention. If it is not of a basic type, then
* an empty QVariant() is returned.
* <table border=1>
* <tr><th>OpenMath type</th> <th>Create a QVariant from this data</th></tr>
* <tr><td>OmIntegerType</td> <td>the int given by OmIntegerNode::getValue()</td>
* </tr>
* <tr><td>OmBigIntegerType</td><td>the QString of digits created from
* OmBigIntegerNode::getDigits(),
* possibly preceded by a minus sign, if
* OmBigIntegerNode::getSign() is negative</td></tr>
* <tr><td>OmFloatType</td> <td>the double given by
* OmFloatNode::getValue()</td></tr>
* <tr><td>OmByteArrayType</td> <td>the QByteArray constructed from the output
* parameters of OmByteArrayNode::getBuffer()</td>
* </tr>
* <tr><td>OmVariableType</td> <td>the QString created from
* OmVariableNode::getName()</td></tr>
* <tr><td>OmStringType</td> <td>the QString created from
* OmStringNode::getBuffer()</td></tr>
* <tr><td>OmWStringType</td> <td>the QString created by QString::fromWCharArray()
* from OmWStringNode::getBuffer()</td></tr>
* <tr><td>OmSymbolType</td> <td>the QStringList containing the two strings
* OmSymbolNode::getName() and
* OmSymbolNode::getCD(), in that order</td></tr>
* </table>
*
* This is tested in test_lob::test_conversions().
*
* \see isBasicType()
*/
QVariant toVariant () const;
/** \brief Whether this wraps an actual OpenMath object
*
* Because this class is a wrapper for OpenMath, it's possible that it was constructed
* with no actual content. This method detects one kind of invalid content (one kind
* of pointer error) by returning whether the internal OmNode pointer is zero.
*
* This is tested by test_lob::test_basics().
*
* \see empty
*/
bool isEmpty () const;
/** \brief Whether this Lob may be modified by routines like set() and setAttribute()
*
* Some Lobs will need to be read-only, so that one can inspect read-only documents
* in Lob format. In such a case, no modifier method such as set() or setAttribute()
* has any effect on the Lob. This function tells you whether the Lob is editable,
* the opposite of read-only.
*
* \see editable
*/
bool isEditable () const;
/** \brief Set this Lob to be modifiable/editable
*
* Although it may seem silly to have a read-only status if you can change it with a
* public method, the main purpose of this status is to make some Lobs read-only from
* scripts. Since scripts cannot access the public methods of a class (only its
* public slots), this is secure. This method is not the setter for the
* <code>editable</code> property; that is intended.
*
* \see editable
*/
void setEditable ( bool on = true );
/** \brief Type of the internal OpenMath node
*
* Simply calls the OmNode::type() function of the wrapped object and returns its result.
*
* Script authors should use the Lob::type property instead.
*
* \return Possible return values are listed
* <a href='http://lurch.sourceforge.net/omcppdoc/all-globals.html'>here</a>.
* If this Lob is empty, returns OmUnknownType.
*
* \see empty
*/
OmType nodeType () const;
/** \brief Changes the wrapped OmNode (in position in its tree) to the given OmNode
*
* This routine replaces the subtree whose root is this Lob's wrapped OmNode with the
* tree whose root is the given OmNode \a s. This involves several steps.
* <ol>
* <li>If the OmNode wrapped in this Lob is another node's child or attribute key or
* value, then extract this subtree from its parent tree. (If it was a key or
* value, extract its partner as well, of course.)</li>
* <li>If \a s is another node's child or attribute key or value,
* then extract it from its parent tree in the same way.</li>
* <li>Insert \a s in the place where this Lob's wrapped OmNode had been;
* this may be a location in its parent's child list, or a location in its
* parent's attribute list (as either a key or a value). In the latter case,
* the formerly extracted partner key/value will be reinserted,
* now partnered with \a s.</li>
* <li>Change this Lob to wrap \a s, and wrap the OmNode that this Lob previously
* wrapped in a temporary Lob, so that it is still owned and cared for by
* \ref LobMemoryManagement "the Lob memory management system".</li>
* </ol>
*
* This routine fails (i.e., does nothing) in the following cases.
* <ul>
* <li>if this Lob wraps the symbol in an
* attribute key-value pair, and \a s is not an OmSymbolNode</li>
* <li>if this Lob wraps an OmNode that is a child or attribute key/value,
* and \a s is either a null pointer or has type OmUnknownType</li>
* <li>if performing the operation would create a
* cyclic parenting or attribution relationship (e.g.,
* <code>myLob.attribute( "a", "b" ).set( myLob.parent() );</code>)</li>
* <li>if this Lob is read-only (not isEditable())</li>
* </ul>
*/
void set ( OmNode* s );
/** \brief Fetch a list of attribute keys, as OpenMath symbols
*
* This will be an ordered list of attribute keys, each of which is an OpenMath
* symbol node with a name and content dictionary. There may be duplicates in this
* list, because the OpenMath Standard permits duplicate keys in the attribute list,
* but querying the attribute returns a unique value because one value takes precedence
* over the others.
*
* Because the Lobs in the returned list are copies of the originals, they are always
* editable, even if the originals were not; modifying them does not alter the
* actual symbols that key this Lob's attributes.
*
* Script authors should use the Lob::keys property instead.
*
* \see numAttributes()
*/
QList<Lob> attributeKeys () const;
/** \brief Convenience function that yields length of attributeKeys()
*
* Rather than call attributeKeys() and ask for its length, this function is more
* efficient because it doesn't involve constructing the full array. Yet the results
* are the same. Returns zero for an empty Lob.
*
* \see attributeKeys()
*/
unsigned int numAttributes () const;
/** \brief Whether the wrapped OpenMath object has the given attribute
*
* \param symbolName the name of the symbol that is the attribute's key
* \param symbolCD the content dictionary of the symbol that is the attribute's key
* \return true if and only if the wrapped OpenMath object is attributed with a
* key-value pair whose key is the symbol described by the given parameters
*
* This is tested by test_lob::test_attributes().
*
* \see attribute(), moveToAttribute()
*/
bool hasAttribute ( QString symbolName, QString symbolCD ) const;
/** \brief Create a new Lob wrapping the specified attribute node within this one
*
* Return a new Lob pointing to the OpenMath object
* in this object's attribute list indexed by the symbol with the given name and
* content dictionary.
*
* If no attribute indexed by the specified symbol exists in the current
* node, an empty Lob is returned.
*
* If this Lob is not editable, then the returned attribute Lob will not be either.
*
* This is tested by test_lob::test_attributes().
*
* \see empty, hasAttribute(), moveToAttribute()
*/
Lob attribute ( QString symbolName, QString symbolCD ) const;
/** \brief Adds or modifies the given attribute in this Lob
*
* If this Lob has an attribute with the specified key, this routine finds it and
* replaces its value with \a newValue. In this case, it functions just as would the
* code <code>attribute( keyName, keyCD ).set( newValue )</code>. For this reason,
* caveats present in the documentation for Lob::set() apply.
*
* If this Lob has no attribute with the
* specified key, this routine adds a new attribute with the specified key, with
* value \a newValue. If this Lob wraps an unattributable node (e.g., unknown type
* or empty Lob), or \a newValue is empty or of unknown type, this routine does nothing.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* \see removeAttribute()
*/
void setAttribute ( QString keyName, QString keyCD, Lob newValue );
/** \brief Removes the key and value of the given attribute
*
* The parameters \a keyName and \a keyCD identify the key to the attribute, but both
* the key and the value are removed. Note that an OpenMath object may be attributed
* with the same key several times, and this removes the first pair, the one that was
* used in any recent lookups of the attribute; a hidden attribute may then become
* visible.
*
* If this Lob does not have an attribute with the given key, this routine does nothing.
* This includes the case when this Lob isEmpty().
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* \see setAttribute()
*/
void removeAttribute ( QString keyName, QString keyCD );
/** \brief The nickname that is an alias for this Lurch Object's ID
*
* Some Lobs may wish to have a nickname that refers to them rather than just an
* ID. For instance, a Lurch Object representing a theorem may wish to be called by
* the name of the theorem. Although this class does not provide any kind of management
* or searching by such nicknames, it provides a place to store them should clients need
* them.
*
* This function looks up a Lob's nickname (the alias for its ID), which
* can be any nonempty string, and returns it. The nickname is stored in the wrapped
* OpenMath object, as an attribute whose key is "nickname" with content dictionary
* "LurchCore," in an OmStringNode. An empty string is returned if no such attribute
* exists.
*
* This is tested in test_ref::test_nicknames().
*
* \see isNicknameReference(), getNicknameReference()
*/
QString getNickname () const;
/** \brief Set the nickname of this Lurch Object
*
* Nicknames are described in getNickname().
* You can set this object's nickname with this function, passing it any string.
* This writes to the nickname attribute (content dictionary LurchCore) as described in
* getNickname().
*
* This routine does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getNickname()
*/
void setNickname ( QString nickname );
/** \brief Assuming the Lob wraps a document, get the document's author
*
* \return if the Lob passes the isDocument() test, then its author is returned as a
* QString; otherwise, the result is undefined (usually an empty QString())
*
* This is tested in test_doc::test_getters().
*
* \see author, title, version, dependencies, URN
*/
QString getAuthor () const;
/** \brief Set the author of this Lurch Object, as if it is a Lurch Document
*
* Although you can set the author of any Lurch Object, it is designed to be used
* with Lurch Documents, as specified in the description of isDocument().
* You can set this object's author with this function, passing it any string.
* This writes to the author attribute (content dictionary LurchCore) as described in
* getAuthor().
*
* This routine does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getAuthor()
*/
void setAuthor ( QString author );
/** \brief Assuming the Lob wraps a document, get the document's title
*
* \return if the Lob has a string attribute called "title" (in content dictionary
* "LurchCore"), as all documents do, then its title is returned as a
* QString; otherwise, the result is undefined (usually an empty QString())
*
* This is tested in test_doc::test_getters().
*
* \see author, title, encoding, version, dependencies, URN
*/
QString getTitle () const;
/** \brief Set the title of this Lurch Object, as if it is a Lurch Document
*
* Although you can set the title of any Lurch Object, it is designed to be used
* with Lurch Documents, as specified in the description of isDocument().
* You can set this object's title with this function, passing it any string.
* This writes to the title attribute (content dictionary LurchCore) as described in
* getTitle().
*
* This routine does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getTitle()
*/
void setTitle ( QString title );
/** \brief Assuming the Lob wraps a document, get the document's encoding language
*
* \return if the Lob has a string attribute called "title" (in content dictionary
* "LurchCore"), as all documents do, then its encoding language is returned as a
* QString; otherwise, the result is undefined (usually an empty QString())
*
* This is tested in test_doc::test_getters().
*
* \see author, title, encoding, version, dependencies, URN
*/
QString getEncodingLanguage () const;
/** \brief Set the encoding language of this Lurch Object, as if it is a Lurch Document
*
* Although you can set the encoding language of any Lurch Object, it is designed to be
* used with Lurch Documents, as specified in the description of isDocument().
* You can set this object's encoding language with this function, passing it any string.
* This writes to the language attribute (content dictionary LurchCore) as described in
* getEncodingLanguage().
*
* This routine does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getEncodingLanguage()
*/
void setEncodingLanguage ( QString lang );
/** \brief Assuming the Lob wraps a document, get the document's version
*
* \return if the Lob passes the isDocument() test, then its version is returned as a
* QString; otherwise, the result is undefined (usually an empty QString())
*
* This is tested in test_doc::test_getters().
*
* \see author, title, version, dependencies, URN
*/
QString getVersion () const;
/** \brief Set the version of this Lurch Object, as if it is a Lurch Document
*
* Although you can set the version of any Lurch Object, it is designed to be used
* with Lurch Documents, as specified in the description of isDocument().
* You can set this object's version with this function,
* provided that you supply a valid version, which is a string containing only
* alphanumerics and dots.
* If you do not provide a string of the correct form, this function does
* nothing.
* This writes to the version attribute (content dictionary LurchCore) as described in
* getVersion().
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getVersion()
*/
void setVersion ( QString version );
/** \brief Assuming the Lob wraps a document, get the document's dependencies
*
* \return if the Lob passes the isDocument() test, then its dependencies are returned as
* a QStringList (the actual dependencies string split by spaces); otherwise, the
* result is undefined (usually an empty QStringList())
*
* This is tested in test_doc::test_getters().
*
* \see author, title, version, dependencies, URN
*/
QStringList getDependencies () const;
/** \brief Set the dependencies of a Lurch Object, as if it is a Lurch Document
*
* Although you can set the dependencies of any Lurch Object, it is designed to be
* used with Lurch Documents, as specified in the description of isDocument().
* You can set this object's dependencies with this function,
* provided that you supply a QStringList, each element of which is a valid Lurch URN,
* as described in isDocument().
* If you do not provide an argument of the correct form, this function does nothing.
* This writes to the dependencies attribute (content dictionary LurchCore) as described
* in getDependencies().
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getDependencies()
*/
void setDependencies ( QStringList dependencies );
/** \brief Assuming the Lob wraps a document, get its URN
*
* \return for a Lob that passes the isDocument() test, its URN is returned as a
* QString, assembled from the requisite parts using makeLurchURN(); for other
* Lobs, the result is undefined (usually an empty QString())
*
* Note that a document does not internally store the optional identifier, because
* that identifier can change with context; see, for example, how LurchEnvironment
* uses those identifiers to label documents with something equivalent to namespaces.
* Thus the return value for this function will never have the
* <code>identifier=urn</code> form mentioned in the documentation for isLurchURN().
*
* This is tested in test_doc::test_getters().
*
* \see author, title, version, dependencies, URN
*/
QString getURN () const;
/** \brief Set the URN of a Lurch Object, as if it is a Lurch Document
*
* Although you can set the URN of any Lurch Object, it is designed to be
* used with Lurch Documents, as specified in the description of isDocument().
* You can set this object's URN with this function,
* provided that you supply a valid one, as described in isLurchURN().
* If you do not provide an argument of the correct form, this function does nothing.
* This writes to the author, title, and version attributes (all from content dictionary
* LurchCore) as described in getURN(); it calls the functions setTitle(), setAuthor(),
* and setVersion() to do its work.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getURN()
*/
void setURN ( QString urn );
/** \brief Assuming the Lob wraps a Lurch Script, get the code for the script
*
* For instance, in the Lurch Script object whose XML representation is given in the
* description of the isScript() member, scriptCode() would return just
* a QString like the following.
* \code
* "function myFunction ( a, b ) {\n"
* " c = a + b;\n"
* " d = 2 * c;\n"
* " return d;\n"
* "}\n"
* "myFunction(7,10);"
* \endcode
*
* If the scriptLanguage() is CoffeeScript, the result will be prefixed with the
* string <code>"# CoffeeScript\n#</code>, to ensure it is distinguishable from JavaScript
* by both human-readable comments and machine-checkable syntax. No other languages
* (of which JavaScript is currently the only option) transform the result in any way.
*
* If the wrapped Lob is not a Lurch Script, the empty QString() is returned.
*
* This is tested by test_func::test_all().
*
* \see isScript(), scriptLanguage(), scriptType()
*/
QString scriptCode () const;
/** \brief Set the code of this Lurch Object, as if it is a Lurch Script
*
* Although you can set the code of any Lurch Object that wraps an OpenMath string
* node, it is designed to be used with Lurch Script,
* as specified in the description of isScript().
* You can set this object's code with this function, passing it any string.
* This changes the contents of the wrapped string node, or does nothing if the
* wrapped object is not a string node.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see scriptCode()
*/
void setScriptCode ( QString code );
/** \brief Assuming the Lob wraps a Lurch Script, get the language attribute
*
* For instance, in the Lurch Script object whose XML representation is given in the
* description of the isScript() member, scriptLanguage() would return
* just the QString "ECMAScript".
*
* If the wrapped Lob is not a Lurch Script, the empty QString() is returned.
*
* This is tested by test_func::test_all().
*
* \see isScript(), scriptCode(), scriptType()
*/
QString scriptLanguage () const;
/** \brief Set the script language of this Lurch Object, as if it is a Lurch Script
*
* Although you can set the script language of any Lurch Object,
* it is designed to be used with Lurch Scripts,
* as specified in the description of isScript().
* You can set this object's script language with this function,
* passing it any string, but currently only the language
* "ECMAScript" is supported; Python may be coming soon.
* This changes the "script language" attribute (content dictionary LurchCore).
*
* This routine does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see scriptLanguage()
*/
void setScriptLanguage ( QString language );
/** \brief Assuming the Lob wraps a Lurch Script, get the script type attribute
*
* For instance, in the Lurch Script object whose XML representation is given in the
* description of the isScript() member, scriptType() would return
* just the QString "auto-run".
*
* If the wrapped Lob is not a Lurch Script, the empty QString() is returned.
*
* This is tested by test_func::test_all().
*
* \see isScript(), scriptCode(), scriptLanguage()
*/
QString scriptType () const;
/** \brief Set the script type of this Lurch Object, as if it is a Lurch Script
*
* Although you can set the script type of any Lurch Object,
* it is designed to be used with Lurch Scripts,
* as specified in the description of isScript().
* You can set this object's script type with this function,
* passing it any string. See LurchEnvironment for how these values are used.
* This changes the "script type" attribute (content dictionary LurchCore).
*
* This routine does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see scriptType()
*/
void setScriptType ( QString type );
/** \brief Whether this Lob wraps an OmBindingType node that binds the given variable
*
* \param var the name of the variable in question
* \return true if and only if isBinding() and one of the bound variables is
* \a var
*
* This routine simply constructs a variable Lob from \a var and calls binds(Lob).
*
* This routine is tested by test_bind::test_basics().
*/
bool binds ( QString var ) const;
/** \brief Whether the named variable occurs free in this Lob
*
* Simply checks to see if \a var is on the list freeVariableNames(\a context).
*
* \see occursFree(Lob,Lob)
*
* This routine is tested in test_bind::test_all_free().
*/
bool occursFree ( QString var, Lob context = Lob() ) const;
/** \brief All free occurrences of the named variable inside this Lob
*
* \param var the name of the variable in question
* \param context Used when computing freeness/boundness, as in boundVariables()
*
* This routine simply constructs a variable Lob from \a var and calls
* freeOccurrences(Lob).
*
* This routine is tested by test_bind::test_all_free().
*/
QVariantList freeOccurrences ( QString var, Lob context = Lob() ) const;
/** \brief Replace every free occurrence of \a var in this Lob with \a term, in place
*
* \param var the name of the variable in question
* \param term the term that will be used to substitute in
* for free occurrences of \a var
* \param context the context in which freeness is computed
*
* This routine simply constructs a variable Lob from \a var and calls
* freeSubstitute(Lob,Lob,Lob).
*
* This routine is tested by test_bind::test_substitution().
*/
void freeSubstitute ( QString var, Lob term, Lob context = Lob() );
/** \brief Rename all instances of a variable bound by this Lob, if it is a quantifier
*
* \param var the name of the variable to replace
* \param newvar the name of the variable with which to replace it
*
* This routine simply constructs a variable Lob from \a var and another from \a newvar
* and calls renameBound(Lob,Lob).
*
* This routine is tested by test_bind::test_substitution().
*/
void renameBound ( QString var, QString newvar );
/** \brief Prepares this object to emit the modified() signal accurately
*
* This registers this Lob as one that should be checked when any Lob makes any
* modifications to any OpenMath object. Thus when one of this Lob's children is
* altered, the Lob that does the modification will notice that it was a child
* (or grandchild, etc.) of this Lob, and tell this Lob to emit the modified() signal.
* To prepare for such lookups, call this function.
*
* Read the description of modified() for more information.
*
* This routine is tested in test_lob_edit::test_read_only().
*
* \see modified(), watchForModifications
*/
void prepareModifiedSignal ();
/** \brief Creates a new Lob wrapping a new OpenMath object from the XML code in the file
*
* Reads the OpenMath XML representation in the given file and creates an OpenMath
* node from it. This node is wrapped in a new Lob, which is
* returned. If any step fails, a new empty Lob is returned. The file is closed
* again at the end of this routine if and only if it was closed when the routine
* was called.
*
* If you pass a nonzero parameter to \a message, this function will store any
* error it encounters in the string to which that pointer points. Ignoring this
* optional parameter will not provide error information, but can be convenient.
*
* Note that whatever nodes are represented in the file will be wrapped in a node of
* unknown type, so that just one node can be returned.
* Even if the file contains the XML representation of only an OpenMath integer, that
* integer will be wraped in a dummy node (type OmUnknownType) before being wrapped in
* the Lob, for consistency's sake. Read more on \link openmath my page of notes about
* OpenMath\endlink, but also note this important C++ pitfall:
* Because of the order of destruction of global/static objects in C++, it is imperative
* not to declare a Lob in the following way.
* \code
* static Lob myLob = Lob::fromXML( "<OMSTR>example</OMSTR>" ).child(); // BAD!!!
* \endcode
* That will occasionally cause a segmentation fault on application exit, on some platforms.
* The reason, I believe, is that the memory allocator sometimes cleans up the global
* object that is the parent before cleaning up the global object that is the child. Instead,
* always do this:
* \code
* static Lob myLob = Lob::fromXML( "<OMSTR>example</OMSTR>" ).child().copy(); // safe
* \endcode
* Note that this is only for static/global objects. Objects declared on the stack are
* cleaned up appropriately at the end of scope, and objects declared on the heap and
* correctly memory managed in the usual way do not cause problems.
*
* This is tested by test_lob::test_qfile_qstring().
*
* \see empty, save(), fromXML(QString)
*/
static Lob fromXML ( QFile& in, QString* message = 0 );
/** \brief Creates a new Lob wrapping a new OpenMath object from the XML code given
*
* Reads the OpenMath XML representation in the given string and creates an OpenMath
* node from it. This node is wrapped in a new Lob, which is
* returned. If any step fails, a new empty Lob is returned.
*
* The notes under fromXML(QFile&) about wrapping in dummy nodes apply here as well.
* Note particularly those about causing segmentation faults by doing so in the wrong context.
*
* This is tested by test_lob::test_qfile_qstring().
*
* \see empty, toString(), fromXML(QFile&)
*/
static Lob fromXML ( QString xml );
/** \brief Creates a new OpenMath object and a new Lob to wrap it, from the given datum
*
* The result will be a Lob that returns true for isBasicType(), according to the
* following table. However, if the given QVariant is not of one of the listed types,
* then the resulting Lob is empty, and thus does not pass isBasicType().
* <table border=1>
* <tr><th>QVariant given</th> <th>Create an OpenMath object of this type</th></tr>
* <tr><td>QVariant::ByteArray</td><td>OmByteArrayType</td></tr>
* <tr><td>QVariant::Double</td> <td>OmFloatType</td></tr>
* <tr><td>QVariant::Int</td> <td>OmIntegerType</td></tr>
* <tr><td>QVariant::LongLong</td> <td>OmBigIntegerType</td></tr>
* <tr><td>QVariant::String</td> <td>OmStringType</td></tr>
* <tr><td>QVariant::UInt</td> <td>OmBigIntegerType</td></tr>
* <tr><td>QVariant::ULongLong</td><td>OmBigIntegerType</td></tr>
* </table>
*
* This is tested in test_lob::test_conversions().
*
* \see isBasicType()
*/
static Lob fromVariant ( QVariant v );
/** \brief Whether the given string contains a Lurch URN
*
* A basic Lurch URN is of the form
* <code>urn:publicid:-:lurch.sourceforge.net:Y+by+X:en:version</code>,
* with X and Y replaced by document title and author email respectively,
* after each has been percent-encoded (see QUrl::percentEncoding()).
* Here is an example.<br>
* &nbsp;&nbsp;&nbsp;&nbsp;<code
* >urn:publicid:-:lurch.sourceforge.net:Basic%20Document+by+jim%40foo.com:en:version
* </code>
*
* This routine verifies that the string splits into five parts with the following
* properties.
* <ol>
* <li>one exactly equal to <code>urn:publicid:-:lurch.sourceforge.net:</code></li>
* <li>the next any nonempty sequence of alphanumerics and dashes, dots, underscores,
* tildes, and percents</li>
* <li>the next exactly equal to <code>+by+</code></li>
* <li>the next any nonempty sequence of alphanumerics plus the same extra characters
* as before</li>
* <li>the last of the form <code>:L:V</code>,
* where L is any two-or-more-letter code (language), and V is any sequence of
* alphanumerics and dots (version)</li>
* </ol>
*
* There is one enhancement to this basic concept; we also define a string of the form
* <code>identifier=urn</code> to be a Lurch URN, if <code>urn</code> is a basic Lurch
* URN, as given above, and <code>identifier</code> is a sequence of alphanumerics
* and underscores that begins with a letter. This is useful in some applications
* (e.g. LurchEnvironment) in giving names to URNs, as in<br>
* &nbsp;&nbsp;&nbsp;&nbsp;<code
* >myAlias_1=urn:publicid:-:lurch.sourceforge.net:Document+by+Jane:en:1.0
* </code>
*
* For fetching the data out of such an URN, see splitLurchURN().
*
* This is tested in test_doc::test_urns().
*/
static bool isLurchURN ( QString testThis );
/** \brief Splits a Lurch URN into its contstituent data
*
* A Lurch URN contains a document title, author, language (optional), and version
* (optional). It may or may not be preceded by an identifier.
* This function splits a valid Lurch URN into these constituent parts,
* and returns them, precent-decoded (see QUrl::fromPercentEncoding()).
*
* \return a QStringList with four or five entries, in which entries three and four
* may be empty strings if the optional language and/or version are not present.
* The fifth component will be present if and only if the Lurch URN came
* preceded by an identifier, in which case it will be that identifier.
* The result will be a completely empty QStringList if the
* given string is not a valid Lurch URN (see isLurchURN()).
*
* This is tested in test_doc::test_urns().
*
* \see isLurchURN()
*/
static QStringList splitLurchURN ( QString splitThis );
/** \brief Create a Lurch URN from author, title, language, and version information
*
* \param title Document title (any string)
* \param author Author's email address (any string with no spaces in it)
* \param language Language code for document content (e.g., "en") (may be left blank)
* \param version Version number (alphanumerics plus periods, may be left blank)
* \param identifier Optional identifier to precede URN, as documented in isLurchURN()
*
* Author email and document title are converted using QUrl::toPercentEncoding().
* No checks are done for whether the parameters fit the requirements just given,
* but if they do not, the resulting string may not pass isLurchURN().
* Optional identifier is only placed at the front of the result if it is nonempty;
* in such a case, the equals sign is inserted and should not be included in the
* \a identifier parameter itself.
*
* This is tested in test_doc::test_urns().
*
* \see isLurchURN(), splitLurchURN()
*/
static QString makeLurchURN ( QString title, QString author,
QString language = QString(), QString version = QString(),
QString identifier = QString() );
/** \brief Remove the optional identifier from in front of a Lurch URN
*
* If \a urn is a Lurch URN preceded by an identifier, as in
* <code>identifier=urn</code>, as described in the documentation for isLurchURN(),
* this function strips off the <code>identifier=</code> part,
* returning just the basic URN. If \a urn has no identifier, it is returned as is.
*/
static QString basicLurchURN ( QString urn );
/** \brief Return the optional identifier preceding an URN, if there is one
*
* If \a urn is a Lurch URN preceded by an identifier, as in
* <code>identifier=urn</code>, as described in the documentation for isLurchURN(),
* this function returns the identifier.
* If \a urn has no identifier, an empty string is returned.
*/
static QString identifierOfURN ( QString urn );
/** \brief Creates a new Lob that satisfies isDocument() and has the given URN
*
* \param urn Should be a basic Lurch URN, as described in isLurchURN().
* If omitted, an URN will be created, with title "New Document",
* author "unknown", language empty, and version "0".
* \param dependencies A list of dependency URNs, which may or may not be basic.
* If omitted, an empty list of dependencies will be used.
*/
static Lob newDocument ( QString urn = QString(),
QStringList dependencies = QStringList() );
signals:
/** \brief Emitted when part of this Lob is modified (read caveats about this signal
* below)
*
* Because a Lob is a wrapper for an OpenMath tree, which does not emit signals when it
* is modified, the Lob class must jump through some hoops to implement this signal's
* emission reliably. Thus you as a client must ensure two conditions hold in order
* for this signal to behave as documented below.
* <ol>
* <li>Ensure that in any Lob in which you wish to use this signal, you call
* prepareModifiedSignal(). (Refer to its documentation for more
* information.)</li>
* <li>Ensure that all edits you perform on OpenMath trees are done through calls to
* member functions of the Lob class. Although you may set up an OpenMath tree
* in another way, after handing it to a Lob and asking it to watch for edits
* (and emit this signal when it sees them), restrict your editing to only
* calling functions in the Lob class.</li>
* </ol>
* If you ensure both of these conditions, then this signal will be emitted whenever
* this Lob's node, any of its children (or grandchildren, and so on), or any of
* their attributes (and so on recursively) are modified in any way.
* For details about the parameter \a change, see the LobChange class documentation.
*
* This signal is tested in test_lob_edit::test_read_only().
*/
void modified ( const LobChange& change );
public slots:
/** \brief Create a deep copy of the Lob, by copying the entire wrapped OpenMath tree
*
* While the copy constructor (or the assignment operator) just copies the wrapper
* object (the Lob), this function also copies the
* internal OpenMath object. Note the consequences of the following code.
* \code
* Lob A = Lob::fromXML( "<OMI>5</OMI>" ); // A == Unknown(Integer 5)
* A = A.child().copy(); // A == Integer 5
* // at this point in the script, the original tree Unknown(Integer 5) is deleted,
* // because there is no way to reference it with Lobs, so memory management nixes it
* \endcode
*
* A deep copy of any node is editable, even if the original was read-only (the
* opposite of editable).
*
* \param changeIDs If this is true (which is the default, if you omit the parameter)
* then after the copy is made, changeIDs() will be called on it,
* with context equal to this Lob. This is useful if you intend to
* later (possibly after modifications) insert the copy into the same
* context as the original, and do not want ID conflicts. If you
* want all IDs preserved in your copy, or wish to call changeIDs()
* yourself with a different context, you can set this parameter to
* false. Read more details about IDs on the
* <a href='idsystem.html'>Lurch ID System page</a>.
*
* This is tested by test_lob::test_copies().
*
* \see copy()
*/
Lob copy ( bool changeIDs = true ) const;
/** \brief Check whether two wrapped OpenMath objects have exactly the same structure
*
* This is different from the equality test in operator==(), in that it does not care if
* the two wrapped objects are <i>the same object in memory</i>, which is what the
* operator tests, but rather this tests for structural equivalence. So two different
* OpenMath trees that have the same nodes in the same arrangement are equivalent,
* but are not operator==().
*
* \param other The Lob to which to compare this object
* \param compareAttributes If this flag is set to true, then the two OpenMath trees are
* checked not only for identical tree structures, but also that
* each node's attributes also match those of the other node.
* Attribute order is only relevant in that later occurrences
* of the same attribute supercede earlier ones; order is
* irrelevant between differently-keyed attributes.
* Values are, of course, compared with equivalent().
* \param exclusions When present, this is a list of name/content dictionary pairs that
* should not be part of the attribute comparison. The exclusions list
* should be a name, its content dictionary, the next name, its content
* dictionary, and so on. For instance, if you wish to compare two
* OpenMath nodes, including all their attributes except their IDs and
* script languages, you might call <code>equivalent( A, B, true,
* QStringList() << "ID" << "LurchCore" << "script language"
* << "LurchCore" )</code>. This parameter is obviously only
* relevant when \a compareAttributes is true.
*
* This routine simply calls equivalent(const OmNode*,const OmNode*,bool,QStringList).
*
* Script writers should be aware of the convenience function "exclusions" described
* in the documentation for addLobsToScriptEngine().
*
* This class is tested by test_lob::test_equivalence(),
* test_lob::test_attributes(), and test_ref::test_exclusion().
*
* \see operator==(), operator!=()
*/
bool equivalentTo ( const Lob& other, bool compareAttributes = false,
QStringList exclusions = QStringList() ) const;
/** \brief Creates a string representation of the node in the XML OpenMath encoding
*
* This is tested by test_lob::test_qfile_qstring().
*
* \see fromXML(QString), save()
*/
QString toString () const;
/** \brief Find the address of this Lob (in an optional parent or container)
*
* A Lob's address is the path from the root of the OpenMath tree to the Lob.
* See the LobAddress class for more information. This routine computes the address
* of this Lob inside a given root, regardless of how many ancestor steps (of any
* type, parent or container) need to be made to get there.
*
* Note that if the optional \a root is not provided, this routine uses its outermost
* parent/container/ancestor as the root. The same behavior holds if the given \a root
* is empty.
*
* If this Lob is not actually a descendant of the root in question, an empty
* LobAddress is returned. This same behavior takes place if you ask for the address
* of a Lob within itself, so take care to distinguish the two in the calling routine.
*/
LobAddress address ( Lob inThis = Lob() ) const;
/** \brief Use a LobAddress to find a descendant of this Lob
*
* A LobAddress class specifies the path from one node in an OpenMath tree downwards,
* through children and/or attributes, to a descendant node. (See the documentation
* for LobAddress for full details.)
*
* This routine takes an \a address and follows that path from this Lob until its end,
* and returns the Lob found there if there is one, or an empty Lob if the address
* turns out to be invalid (i.e., contain steps that are not possible in the tree
* under this Lob).
*
* The \a offset parameter is largely for internal use during recursion, but callers
* may use it; if it is nonzero, the routine only pays attention to the steps in the
* address beginning with \a offset. For example, if \a offset == 2, then the first
* two steps of the address are ignored, and the path from steps 2 through the end
* is used instead.
*/
Lob index ( LobAddress address, unsigned int offset = 0 );
/** \brief Whether the Lurch Object wraps an OpenMath object of a basic type
*
* The following OpenMath types from the C++ library represent OpenMath basic types.
* This function returns true if this object is not empty (Lob::empty) and its type is
* one of these types.
* <ul>
* <li>OmIntegerType</li>
* <li>OmBigIntegerType</li>
* <li>OmFloatType</li>
* <li>OmByteArrayType</li>
* <li>OmVariableType</li>
* <li>OmStringType</li>
* <li>OmWStringType</li>
* <li>OmSymbolType</li>
* </ul>
*
* This is tested in test_lob::test_conversions().
*
* \see toVariant()
*/
bool isBasicType () const;
/** \brief Number of children of the wrapped OpenMath node
*
* This will be zero for a final (leaf) node, and for an empty application node.
* It is zero if this Lob is empty. It will be nonzero otherwise.
*
* This is tested by test_lob::test_tree().
*
* \see empty
*/
unsigned int numChildren () const;
/** \brief Creates a new Lob wrapping the chosen child
*
* \param index The index of the desired child. It defaults to zero, meaning the first
* child. Any value up to but not including numChildren() is a valid value.
* \return A new Lob in any case, wrapping the corresponding child if the index is
* less than numChildren(). Otherwise, the new Lob returned is empty.
*
* If this Lob is not editable, then the returned child Lob will not be either.
*
* This is tested by test_lob::test_tree().
*
* \see empty, numChildren()
*/
Lob child ( unsigned int index = 0 ) const;
/** \brief Whether the wrapped OpenMath object has a parent (is another node's child)
*
* This is tested by test_lob::test_tree().
*
* \see parent(), isDocument(), hasContainer()
*/
bool hasParent () const;
/** \brief Creates a new Lob wrapping the parent of this one
*
* If this object wraps a node that is no other node's child, then this will return an
* empty Lob, meaning there is no parent. You can check this first with hasParent().
*
* If this Lob is not editable, then the returned parent Lob will not be either.
*
* This is tested by test_lob::test_tree().
*
* \see empty, document
*/
Lob parent () const;
/** \brief Whether the wrapped OpenMath object has a container (is an attribute key/value)
*
* If a node N is attributed by the symbol/node (key/value) pair (K,V), then we say
* that N is the "container" of K and also of V. So <code>K.container()</code> and
* <code>V.container()</code> should both be N. This is distinct from the parent()
* function, which is used for parent/child relationships.
*
* This is tested by test_lob::test_tree().
*
* \see container(), isDocument(), hasParent()
*/
bool hasContainer () const;
/** \brief Creates a new Lob wrapping the container of this one
*
* If this object wraps a node that is not used as a key or value to attribute another
* node, then this will return an empty Lob, meaning there is no container.
* So "container" here means "the node which this node is attributing."
* You can check this first with hasContainer().
*
* If this Lob is not editable, then the returned container Lob will not be either.
*
* This is tested by test_lob::test_tree().
*
* \see empty, document
*/
Lob container () const;
/** Whether \a maybeAncestor is an ancestor of this Lob
*
* This check involves a walk upward through both parent() and container() relationships,
* searching for \a maybeAncestor. It returns true iff \a maybeAncestor is found before
* reaching a Lob with no parent/container. A Lob counts as its own ancestor.
*
* This is used internally for guarding against creating non-trees
* in routines such as addChild(), insertChild(), insertPreviousSibling(), and
* insertNextSibling(). You can use it externally for other things, of course.
*/
bool hasAsAncestor ( const Lob maybeAncestor ) const;
/** \brief Whether the wrapped OpenMath object has a next sibling
*
* If this object is empty or is no other node's child, this defaults to false.
* Otherwise it is determined by
* the position of this object within the children array of its parent.
* To get the next sibling, call nextSibling().
*
* This is tested by test_lob::test_tree().
*
* \see empty, nextSibling()
*/
bool hasNextSibling () const;
/** \brief Create a new Lob wrapping the next sibling of this one
*
* If this object has no next sibling, then this returns an empty Lob.
* You can check this first by calling hasNextSibling().
*
* If this Lob is not editable, then the returned sibling Lob will not be either.
*
* This is tested by test_lob::test_tree().
*
* \see hasNextSibling()
*/
Lob nextSibling () const;
/** \brief Whether the wrapped OpenMath object has a previous sibling
*
* If this object is empty or is no other node's child, this defaults to false.
* Otherwise it is determined by
* the position of this object within the children array of its parent.
* To get the previous sibling, call previousSibling().
*
* This is tested by test_lob::test_tree().
*
* \see empty, previousSibling()
*/
bool hasPreviousSibling () const;
/** \brief Create a new Lob wrapping the previous sibling of this one
*
* If this object has no previous sibling, then this returns an empty Lob.
* You can check this first by calling hasPreviousSibling().
*
* If this Lob is not editable, then the returned sibling Lob will not be either.
*
* This is tested by test_lob::test_tree().
*
* \see hasPreviousSibling()
*/
Lob previousSibling () const;
/** \brief Convenience function that calls hasAttribute(QString,QString)
*
* This function lifts out the symbol's name and content dictionary,
* then calls hasAttribute(QString,QString) with those values.
* This is the function exposed to script writers, who usually obtain attribute keys
* as symbol Lobs, perhaps using attributeKeys().
* If \a symbolLob is not a Lob that wraps an OmSymbolNode, this function returns false.
*
* \see hasAttribute(QString,QString)
*/
bool hasAttribute ( Lob symbolLob ) const;
/** \brief Convenience function that calls attribute(QString,QString)
*
* This function lifts out the symbol's name and content dictionary,
* then calls attribute(QString,QString) with those values.
* This is the function exposed to script writers, who usually obtain attribute keys
* as symbol Lobs, perhaps using attributeKeys().
* If \a symbolLob is not a Lob that wraps an OmSymbolNode, this function returns an
* empty Lob.
*
* \see attribute(QString,QString)
*/
Lob attribute ( const Lob& symbolLob ) const;
/** \brief Convenience function that calls setAttribute(QString,QString,Lob)
*
* This function lifts out the symbol's (key's) name and content dictionary,
* then calls setAttribute(QString,QString,Lob) with those values.
* This is the function exposed to script writers, who usually obtain attribute keys
* as symbol Lobs, perhaps using attributeKeys().
* If \a key is not a Lob that wraps an OmSymbolNode, this function does nothing.
*
* \see setAttribute(QString,QString,Lob)
*/
void setAttribute ( Lob key, Lob value );
/** \brief Convenience function that calls removeAttribute(QString,QString)
*
* This function lifts out the symbol's name and content dictionary,
* then calls removeAttribute(QString,QString) with those values.
* This is the function exposed to script writers, who usually obtain attribute keys
* as symbol Lobs, perhaps using attributeKeys().
* If \a symbolLob is not a Lob that wraps an OmSymbolNode, this function does nothing.
*
* \see removeAttribute(QString,QString)
*/
void removeAttribute ( Lob symbolLob );
/** \brief Changes the current Lob (in position in a tree) to the given Lob
*
* This is just a convenience function that calls set(OmNode*) with the wrapped
* OmNode from \a s as its parameter. Refer to the documentation for that function
* for full details.
*
* \see set(OmNode*)
*/
void set ( Lob s );
/** \brief Remove this Lob from its parent or container
*
* If this Lob is a child of another Lob, then it will be deparented as if
* <code>parent().removeChild( i )</code> were called,
* for the appropriate value of <code>i</code>.
*
* If this Lob is an attribute key or value of another Lob,
* then it will be removed from the attributed Lob by removing the entire
* key-value pair in which it sits.
*
* If the Lob satisfies neither hasParent() nor hasContainer(), this function
* does nothing.
*/
void remove ();
/** \brief Inserts the given Lob as a child of the current one
*
* After this routine, <code>child(index)</code> will give a Lob equal (==) to
* \a newChild.
* Exceptions include if this Lob is empty, or a final Lob, so that it may not have
* children (e.g., an integer or a symbol), or if it has type OmUnknownType,
* or if \a index is larger than the current
* number of children.
* Further exceptions include if \a newChild is empty or of type OmUnknownType,
* or an ancestor of this Lob.
* In those cases, this routine does nothing.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* If \a newChild had a parent before this routine was called, then this routine will
* reparent it using the routine Lob::set(Lob).
*
* \see removeChild(), addChild()
*/
void insertChild ( uint index, Lob newChild );
/** \brief Appends the given Lob as this Lob's new last child
*
* After this routine, <code>child(numChildren()-1)</code> will give a Lob equal (==) to
* \a newChild.
* Exceptions include if this Lob is empty or a final Lob, so that it may not have
* children (e.g., an integer or a symbol), or when it has type OmUnknownType.
* Further exceptions include if \a newChild is empty or of type OmUnknownType,
* or an ancestor of this Lob.
* In those cases, this routine does nothing.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* If \a newChild had a parent before this routine was called, then this routine will
* reparent it using the routine Lob::set(Lob).
*
* \see removeChild(), addChild()
*/
void addChild ( Lob newChild );
/** \brief Removes the specified child
*
* After this routine, the node that had been <code>child(index)</code> will be
* deparented from this one, and deleted if and only if no other Lobs wrap it or any
* other nodes to which it is connected. This node will have one fewer child.
*
* If \a index is greater than or equal to <code>numChildren()</code>, this routine
* does nothing.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* \see insertChild(), addChild()
*/
void removeChild ( uint index = 0 );
/** \brief Inserts the given Lob after this one in the parent's list of children
*
* After this routine, <code>nextSibling()</code> will give a Lob equal (==) to \a s.
* There are two exceptions.
* If this Lob is not any other Lob's child, in which case the
* notion of siblings is meaningless, then this routine does nothing. This happens when
* <code>!hasParent()</code> and when this node is one of its parent's attributes, as
* opposed to one of its parent's children.
* Also, if the parent is of type OmUnknownType, one cannot append children to it, so
* this routine does nothing.
*
* This routine also does nothing if this Lob is read-only (not isEditable()),
* or if \a newSibling is one of its ancestors.
*
* If \a newSibling had a parent before being assigned, then this routine will reparent
* it using the routine Lob::set(Lob).
*
* \see insertPreviousSibling(), removeNextSibling(), removePreviousSibling()
*/
void insertNextSibling ( Lob newSibling );
/** \brief Inserts the given Lob before this one in the parent's list of children
*
* After this routine, <code>previousSibling()</code> will give a Lob equal (==) to \a s.
* There are two exceptions.
* If this Lob is not any other Lob's child, in which case the
* notion of siblings is meaningless, then this routine does nothing. This happens when
* <code>!hasParent()</code> and when this node is one of its parent's attributes, as
* opposed to one of its parent's children.
* Also, if the parent is of type OmUnknownType, one cannot append children to it, so
* this routine does nothing.
*
* This routine also does nothing if this Lob is read-only (not isEditable()),
* or if \a newSibling is one of its ancestors.
*
* If \a newSibling had a parent before being assigned, then this routine will reparent
* it using the routine Lob::set(Lob).
*
* \see insertNextSibling(), removeNextSibling(), removePreviousSibling()
*/
void insertPreviousSibling ( Lob newSibling );
/** \brief Removes the Lob after this one in the parent's list of children
*
* After this routine, there will be one fewer child to this Lob's parent, and the
* missing one will be what was <code>nextSibling()</code> before this routine was
* called.
* There are a few exceptions. If this Lob is not any other Lob's child,
* in which case the notion of siblings is meaningless, then this routine does nothing.
* This happens when <code>!hasParent()</code> and when this node is one of its parent's
* attributes, as opposed to one of its parent's children.
* The routine also does nothing if <code>!hasNextSibling()</code>.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* \see insertNextSibling(), removePreviousSibling()
*/
void removeNextSibling ();
/** \brief Removes the Lob before this one in the parent's list of children
*
* After this routine, there will be one fewer child to this Lob's parent, and the
* missing one will be what was <code>previousSibling()</code> before this routine was
* called.
* There are a few exceptions. If this Lob is not any other Lob's child,
* in which case the notion of siblings is meaningless, then this routine does nothing.
* This happens when <code>!hasParent()</code> and when this node is one of its parent's
* attributes, as opposed to one of its parent's children.
* The routine also does nothing if <code>!hasPreviousSibling()</code>.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* \see insertPreviousSibling(), removeNextSibling()
*/
void removePreviousSibling ();
/** \brief How many comments are attached to this Lob
*
* A comment is attached to a Lob if it precedes it in the XML encoding of the
* Lob. For instance, the following XML describes a Lob whose first child has
* one comment and whose second child has two.
* <pre>
* &lt;OMA&gt;
* &lt;!-- This comment modifies the addition symbol. --&gt;
* &lt;OMS name="addition" cd="arithmetic"/&gt;
* &lt;!-- This comment modifies the number one. --&gt;
* &lt;!-- So does this one; no comment modifies the two. --&gt;
* &lt;OMI&gt;1&lt;/OMI&gt;
* &lt;OMI&gt;2&lt;/OMI&gt;
* &lt;/OMA&gt;
* </pre>
* The comments that precede a Lob are stored in it, and this function returns how
* many there are, zero or more.
*/
unsigned int numComments ();
/** \brief The comment at the given index, returned as a string
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function returns a string containing the <i>i</i><sup>th</sup> comment for
* this Lob, or an empty string if the Lob is empty or \a i is greater than or equal
* to the number of comments the Lob contains. (Zero-based indexing.)
* Any leading and trailing space will be removed from the string before it is returned.
* (See documentation for changeComment() for details on why.)
*/
QString comment ( unsigned int i );
/** \brief Delete the comment at the given index
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function deletes the <i>i</i><sup>th</sup> comment for this Lob, or does
* nothing if the Lob is empty or \a i is greater than or equal
* to the number of comments the Lob contains. (Zero-based indexing.)
*/
void removeComment ( unsigned int i );
/** \brief Replace the comment at the given index with the given text
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function overwrites the <i>i</i><sup>th</sup> comment for this Lob with
* \a text, or does nothing if the Lob is empty or \a i is greater than or equal
* to the number of comments the Lob contains. (Zero-based indexing.)
*
* To every \a text parameter is prepended and appended one space character,
* because otherwise the INRIA OM library does not correctly handle comments.
* For instance, if you set a comment as "foo" it creates XML code for that comment
* as <code>&lt;!--foo--&gt;</code>, which it cannot then read back in.
* Note how this works sensibly together with the removal of leading and trailing
* space in routines such as comment().
*/
void changeComment ( unsigned int i, QString text );
/** \brief Insert a new comment before the comment at the given index
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function inserts a new comment as the <i>i</i><sup>th</sup> comment for
* this Lob, bumping the former <i>i</i><sup>th</sup> comment and all later ones
* to one-higher indexes. This routine does nothing if the Lob is empty or \a i is
* greater than to the number of comments the Lob contains. (Zero-based indexing.)
* If \a i equals the number of comments before this routine is executed, then its
* effect is the same as that of appendComment().
*
* To every \a text parameter is prepended and appended one space character,
* because otherwise the INRIA OM library does not correctly handle comments.
* For instance, if you set a comment as "foo" it creates XML code for that comment
* as <code>&lt;!--foo--&gt;</code>, which it cannot then read back in.
* Note how this works sensibly together with the removal of leading and trailing
* space in routines such as comment().
*/
void insertComment ( unsigned int i, QString text );
/** \brief Add a new comment to the end of this Lob's comment list
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function adds the given text as a new comment with index equal to the former
* number of comments. This function does nothing if this Lob isEmpty().
*
* To every \a text parameter is prepended and appended one space character,
* because otherwise the INRIA OM library does not correctly handle comments.
* For instance, if you set a comment as "foo" it creates XML code for that comment
* as <code>&lt;!--foo--&gt;</code>, which it cannot then read back in.
* Note how this works sensibly together with the removal of leading and trailing
* space in routines such as comment().
*/
void appendComment ( QString text );
/** \brief This Lob's comments, returned all together as one list
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function returns the comments for this Lob in the same order that they would
* be queried using comment(). For example, the text of all comments could be assembled
* together into paragraphs easily using <code>comments().join( "\n" );</code>.
* Any leading and trailing space will be removed from each comment before the list
* is returned, as in comment().
*/
QStringList comments ();
/** \brief Replace the full list of this Lob's comments with a new list
*
* See numComments() for a description of how XML comments are associated with (and
* stored in) the Lobs that follow them.
*
* This function does nothing if this Lob isEmpty(). Otherwise, it begins by erasing
* all existing comments, and then proceeds to append all comments in \a all, in order,
* so that when this routine is finished, commeent(i) == all[i] for each index i.
*
* To every element of \a all is prepended and appended one space character,
* because otherwise the INRIA OM library does not correctly handle comments.
* For instance, if you set a comment as "foo" it creates XML code for that comment
* as <code>&lt;!--foo--&gt;</code>, which it cannot then read back in.
* Note how this works sensibly together with the removal of leading and trailing
* space in routines such as comment().
*/
void setComments ( QStringList all );
/** \brief Whether the wrapped object fits the definition of a Lurch Document
*
* The OpenMath node is a Lurch Document if and only if the following criteria all hold.
* <ol>
* <li>The Lob is nonempty, and its node has no parent.</li>
* <li>The node is of type OmApplicationType and its first child is the symbol
* with name "document" in content dictionary "LurchCore".</li>
* <li>It has an attribute whose key is
* <code>&lt;OMS name="author" cd="LurchCore"/></code> and whose value is an
* OmStringNode that is nonempty (the author, usually as an email address).</li>
* <li>It has an attribute whose key is
* <code>&lt;OMS name="title" cd="LurchCore"/></code> and whose value is an
* OmStringNode that is nonempty (the document's title).</li>
* <li>It has an attribute whose key is
* <code>&lt;OMS name="dependencies" cd="LurchCore"/></code> and whose value is an
* OmStringNode that is a list of URNs separated by spaces (those documents on
* which this one depends). Each of these URNs must satisfy isLurchURN().</li>
* </ol>
*
* Lurch Documents may also have the optional attribute "version" (with cd LurchCore).
* If this option is present, it should be a string of alphanumerics and dots.
* But this requirement is not checked by isDocument().
*
* This is tested in test_doc::test_isdoc().
*/
bool isDocument () const;
/** \brief Whether the wrapped OpenMath object is a Lurch Script
*
* An OpenMath object can be interpreted as a Lurch Script if all the following
* criteria are met.
* <ul>
* <li>It is an OmStringNode.</li>
* <li>It has an attribute keyed by the symbol named "script language" in content
* dictionary "LurchCore" whose value is a nonempty OmStringNode.</li>
* </ul>
* It may optionally have an attribute keyed by the symbol named "script type" in
* content dictionary "LurchCore" whose value is a string node containing information
* about how this script is to be used; see LurchEnvironment for details on the use
* of this attribute.
*
* The script itself should be a string containing any code in the scripting language
* specified in the "script language" attribute. For instance, here is a valid Lurch
* Script OpenMath object.
* <pre>
* &lt;OMATTR>
* &lt;OMATP>
* &lt;OMS name="script language" cd="LurchCore"/>
* &lt;OMSTR>Javascript&lt;/OMSTR>
* &lt;OMS name="script type" cd="LurchCore"/>
* &lt;OMSTR>auto-run&lt;/OMSTR>
* &lt;/OMATP>
* &lt;OMSTR>function myFunction ( a, b ) {
* c = a + b;
* d = 2 * c;
* return d;
* }
* myFunction(7,10);&lt;/OMSTR>
* &lt;/OMATTR>
* </pre>
*
* This is tested by test_func::test_all().
*
* \see scriptCode(), scriptLanguage(), scriptType()
*/
bool isScript () const;
/** \brief Whether any subtree of this Lob is a script of the given type
*
* \param type If provided, then only scripts whose scriptType() equals this parameter
* are considered; others will not cause a return value of true.
* \return True if and only if there is some descendant of this Lob that passes the
* isScript() test and whose scriptType() equals \a type. (This latter check
* is only done if !type.isEmpty()).
*/
bool containsScript ( QString type = QString() ) const;
/** \brief Create a Lurch ID Reference to this object
*
* This returns a Lob that wraps a newly created OpenMath object, which is a Lurch ID
* Reference that refers to this Lob.
* To learn how Lurch ID References are formatted, see the documentation for
* isIDReference().
*
* For full information on the Lurch ID System, refer to the
* <a href='idsystem.html'>Lurch ID System page</a>.
*
* \see isIDReference(), referent()
*/
Lob reference ();
/** \brief Find the Lob that this object (treated as a Lurch ID Reference) references
*
* This returns the Lob to which this object refers, if there is one.
* This object must be a Lurch ID Reference (see isIDReference()) or the result will
* be an empty Lob. There must be a Lob with the ID this object references in the
* same OpenMath tree as this object. It returns the closest one, where "closest"
* means "has the closest common ancestor."
*
* For full information on the Lurch ID System, refer to the
* <a href='idsystem.html'>Lurch ID System page</a>.
*
* \see isIDReference(), reference()
*/
Lob referent () const;
/** \brief Whether this Lurch Object is a Lurch Reference to another Lurch Object's ID
*
* A Lurch Reference is a Lurch Object that wraps an OmStringNode containing the unique
* ID or nickname of some Lurch Object (the object being referenced). It must be one
* one of the following two types.
* <ul>
* <li><em>an ID reference</em>:
* the ID of the object being referenced is a sequence of decimal digits
* (the result of applying Lob::getID to the object being referened) preceded
* by the two characters "id". In this
* case this Lurch Reference object must have an attribute
* whose key is the symbol "reference" in content dictionary "LurchCore" and whose
* value is the OmStringNode containing the literal string "ID"</li>
* <li><em>a nickname reference</em>: the nickname of the object being referenced is
* any string which is interpreted as a nickname for that object. In this case
* this Lurch Reference object must have an attribute whose
* key is the symbol "reference" in content dictionary "LurchCore" and whose
* value is the OmStringNode containing the literal string "nickname"</li>
* </ul>
*
* \return true if and only if the object satisfies the criterion for an ID reference,
* the first of the two types mentioned above
*
* This is tested in test_ref::test_ids().
*
* \see getIDReference(), isNicknameReference(), reference(), referent()
*/
bool isIDReference () const;
/** \brief Whether this Lurch Object is a Lurch Reference to another Lurch Object's
* nickname
*
* A Lurch Reference is a Lurch Object that wraps an OmStringNode of one of two types,
* as documented in the isIDReference() function.
*
* \return true if and only if the object satisfies the criterion for a nickname
* reference, the second of the two types documented in the isIDReference()
* function
*
* This is tested in test_ref::test_nicknames().
*
* \see getNicknameReference(), getNickname(), isIDReference()
*/
bool isNicknameReference () const;
/** \brief Assuming this Lurch Object is an ID reference, this returns the ID referenced
*
* A Lob is an ID reference if it fits the description of such objects given in
* the documentation for the function isIDReference(). If it is one, then this
* function returns the ID referenced, as a string. Otherwise, it returns an
* empty string.
*
* This is tested in test_ref::test_ids().
*
* \see getNicknameReference(), isIDReference(), reference(), referent()
*/
QString getIDReference () const;
/** \brief Set the ID to which this Lurch Object refers, as if it is a Lurch ID Reference
*
* Although you can set the ID referent for any Lurch Object that wraps an OpenMath
* string node, it is designed to be used with Lurch ID References,
* as specified in the description of isIDReference().
* You can set this object's ID referent with this function, passing it any valid ID,
* which means any string of digits.
* This changes the contents of the wrapped string node, or does nothing if the
* wrapped object is not a string node or the given id is invalid.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getIDReference()
*/
void setIDReference ( QString id );
/** \brief Assuming this Lurch Object is a nickname reference, this returns the nickname
*
* A Lob is a nickname reference if it fits the description of such objects given
* in the documentation for the function isNicknameReference(). If it is one, then this
* function returns the nickname. If it is not one, then this function returns
* QString(), an invalid nickname.
*
* This is tested in test_ref::test_nicknames().
*
* \see getIDReference(), isNicknameReference(), getNickname()
*/
QString getNicknameReference() const;
/** \brief Set the nickname to which this Lurch Object refers,
* as if it is a Lurch Nickname Reference
*
* Although you can set the nickname referent for any Lurch Object that wraps an
* OpenMath string node, it is designed to be used with Lurch Nickname References,
* as specified in the description of isNicknameReference().
* You can set this object's nickname referent with this function, passing it any
* string. This changes the contents of the wrapped string node, or does nothing if
* the wrapped object is not a string node.
*
* This routine also does nothing if this Lob is read-only (not isEditable()).
*
* This is tested in test_script::test_setters().
*
* \see getNicknameReference()
*/
void setNicknameReference ( QString nickname );
/** \brief Instruct this Lob to act as a context for Lurch IDs
*
* The Lurch ID system is complex enough that it has its own page in the source code
* documentation. See <a href='idsystem.html'>The Lurch ID System page</a> for more
* information about what a context for IDs is.
*
* \param on Instruct this Lob to act as a context for IDs if and only if this parameter
* is true. Otherwise, instruct it to stop acting as an ID context.
*/
void setIDContext ( bool on = true );
/** \brief Look up this Lob's ID
*
* The ID is stored in the attribute whose key has name ID and content dictionary
* LurchCore.
* The attribute's value is an OmStringNode containing "id" followed by
* a sequence of decimal digits.
* (This is distinct from the OpenMath id attribute, which is for
* OpenMath References, which are for compacting documents for storage,
* and have no actual meaning for the mathematics represented by the document.)
* If the content of the specified attribute is not of this form,
* then the Lob is said to not have an ID, and this function will return an empty
* string, as if there were no ID attribute at all.
*
* The Lob class provides the public functions reference() and referent() for dealing
* with IDs; script authors only need to deal with those.
* For a detailed description of the Lurch ID System,
* see the <a href='idsystem.html'>Lurch ID System page</a>.
*
* \see setID(), reference(), referent()
*/
QString getID () const;
/** \brief Ask whether this Lob is acting as a context for Lurch IDs
*
* \see setIDContext()
*/
bool isIDContext () const;
/** \brief Change each ID in this tree to a new one and keep internal references synced
*
* This routine traverses the OpenMath tree wrapped by this Lob, and for each node
* with an ID, it replaces the ID with <code>context.getNewID()</code>.
* As it does so, it creates a conversion function from old ID values to new ones.
* The tree is then traversed again, applying that conversion
* function to all ID references, to keep them up to date.
* ID references whose IDs are not in the domain of such a function are external
* (non-local) references, and are not converted.
*
* \param context If not supplied, this defaults to an empty Lob, which gets converted
* internally to this Lob, and thus the default means "use this Lob's
* context," in the sense of setIDContext() and getNewID().
* If supplied, the new IDs will be computed in the context
* \a context, in the sense that it will be the Lob in which getNewID()
* is called, as stated above.
*
* This is called after making a copy of a Lob unless you explicitly ask for that
* not to happen; see copy().
*/
void changeIDs ( Lob context = Lob() );
/** \brief Ensure no two descendant nodes under this tree have duplicate Lurch IDs
*
* This function traverses the subtree under this Lob and ensures that no ID is used
* for more than one Lurch Object.
*
* \return True if and only if no ID is used more than once.
*/
bool checkUniqueIDs () const;
/** \brief Ensure no two descendant nodes under this tree have duplicate nicknames
*
* This function is analogous to checkUniqueIDs(), except for nicknames.
*
* This routine is tested in test_lenv::test_doc_and_deps(),
* because it is used by LurchEnvironment::load().
*
* \see checkUniqueIDs()
*/
bool checkUniqueNicknames () const;
/** \brief Remove all unused IDs in all descendants
*
* Nodes can be assigned Lurch IDs with ensureUniqueIDs(); this adds an attribute to
* every node, and perhaps even nearly every attribute as well.
* This makes the tree take up much more space in memory and take longer to process
* for various operations (such as conversion of old IDs into new ones in
* ensureUniqueIDs()). It is good to be able to drop unused IDs sometimes, for example
* before saving a document to the filesystem.
*
* This routine removes the Lurch ID of every descendant node except those whose IDs
* are referenced in a Lurch ID Reference elsewhere in this tree.
*/
void removeExtraIDs ();
/** \brief List all IDs or Nicknames in the wrapped OpenMath tree
*
* This does not list IDs or nicknames that appear only in references; it lists all
* the IDs and nicknames that actually appear as attributes of nodes in the tree.
*
* \param nicknameOrID Set this to the string "ID" to search for IDs, or the string
* "nickname" to search for nicknames. It is case sensitive.
* Behavior for other values of this parameter is undefined.
*/
QStringList listAllLabels ( QString nicknameOrID ) const;
/** \brief Whether this Lob wraps an OmBindingType OpenMath object
*
* Simply returns the comparison of nodeType() with OmBindingType.
*
* This routine is tested by test_bind::test_basics().
*/
bool isBinding () const;
/** \brief Whether this Lob wraps an OmBindingType node that binds the given variable
*
* \param var the variable in question
* \return true if and only if isBinding() and one of the bound variables matches
* \a var when compared using compareVariables()
*
* This routine is tested by test_bind::test_basics().
*/
bool binds ( Lob var ) const;
/** \brief All variables bound by this Lob, or any of its ancestors, up to \a context
*
* \param context The context in which "bound" is to be interpreted; for instance,
* even if this Lob is within some outer Lob that binds x, if that
* outer Lob is outside of \a context, x does not count as bound.
* This defaults to the outermost context (the root of the tree),
* a default which takes effect if a context is given that is not
* actually an ancestor of this Lob.
* \return A list of Lobs (as a QVariantList, because a Lob can be converted to and
* from a QVariant) that are the bound variables. If R is the result, access
* each of its members as a Lob using R[i].value<Lob>().
*
* This routine is tested in test_bind::test_all_bound().
*/
QVariantList boundVariables ( Lob context = Lob() ) const;
/** \brief Names of all variables bound by this Lob or its ancestors up to \a context
*
* This functions just like boundVariables(), except that only the variable names
* are returned. This is all that is relevant in most cases, unless attributes are
* taken into account by compareVariables(), which is not the default.
*
* This routine is tested in test_bind::test_all_bound().
*/
QStringList boundVariableNames ( Lob context = Lob() ) const;
/** \brief All variables that appear free in this Lob, with reference to \a context
*
* \param context The context in which freeness/boundness is determined. A quantifier
* only counts as binding a variable (for the purposes of this call) if
* it appears inside the tree \a context. If not supplied, this defaults
* to the whole tree, meaning all quantifiers are relevant.
* \param boundAbove Callers should not supply this; it is used internally for
* recursion. It is either false, meaning the data has yet to be
* computed, or it is a QVariantList, meaning the list of variables
* bound by quantifiers strictly above the current Lob (and inside
* \a context).
*
* This routine is tested in test_bind::test_all_free().
*/
QVariantList freeVariables ( Lob context = Lob(), QVariant boundAbove = false ) const;
/** \brief Names of all variables that appear free in this Lob, within \a context
*
* This functions just like freeVariables(), except that only the variable names
* are returned. This is all that is relevant in most cases, unless attributes are
* taken into account by compareVariables(), which is not the default.
*
* This routine is tested in test_bind::test_all_free().
*/
QStringList freeVariableNames ( Lob context = Lob() ) const;
/** \brief Whether the variable occurs free in this Lob
*
* Simply checks to see if \a var is on the list freeVariables(\a context).
*
* \see occursFree(QString,Lob)
*
* This routine is tested in test_bind::test_all_free().
*/
bool occursFree ( Lob var, Lob context = Lob() ) const;
/** \brief Whether this Lob (which must wrap a variable) is free in the given context
*
* \param context Functions as in freeVariables() and related routines.
* If not provided, it is assumed to be the whole tree in which this
* Lob sits.
* \return True if and only if this Lob is a variable and it is free in the given
* context. In particular, if this Lob is not a variable, false is returned.
*
* This routine is tested in test_bind::test_all_free().
*/
bool isFree ( Lob context = Lob() ) const;
/** \brief The ancestor Lob which binds this Lob (if it is a variable)
*
* \return If this Lob is a variable, then this function returns the Lob which is the
* closest ancestor of this one that binds this variable (as in binds()),
* if one exists. If one does not exist, or if the Lob is not a variable,
* then an empty Lob is returned.
* \param context If provided, the computation is done only within the given subtree
* \a context; otherwise, the entire tree in which this Lob resides
* is used for the computation. In other words, no ancestor strictly
* above \a context is searched.
*
* This routine is tested in test_bind::test_all_bound().
*/
Lob binderOf ( Lob context = Lob() ) const;
/** \brief All free occurrences of the given variable inside this Lob
*
* Comparisons are done using compareVariables(), as always, but the resulting list may
* contain repetitions in the compareVariables() sense, because the point is to return
* occurrences, and no occurrence will appear on the list more than once. As with
* freeVariables() and similar routines, the result is a list of variants, each element
* \a v of the list convertible to a Lob using v.value<Lob>().
*
* \param var The variables whose occurrences are to be returned
* \param context Used when computing freeness/boundness, as in boundVariables()
*
* This routine is tested by test_bind::test_all_free().
*/
QVariantList freeOccurrences ( Lob var, Lob context = Lob() ) const;
/** \brief Replaces every free occurrence of \a var in this Lob with \a term, in place
*
* This is equivalent to calling L.set(term.copy()) on every L in freeOccurrences(var).
* This routine in fact does exactly that, passing the \a context parameter directly
* on to the call to freeOccurrences().
*
* Note that the subsitution is done regardless of whether variables in \a term become
* bound in this Lob by the substitution; you can perform your own more subtle
* substitution by code like the following.
* \code
* foreach ( const QVariant& v, myLob.freeOccurrences( var, context ) ) {
* Lob occ = v.value<Lob>();
* if ( occ.freeToSubstitute( term, context ) ) // or any decision function here
* occ.set( term.copy() );
* }
* \endcode
*
* This routine is simply code like the above, but with no "if" clause.
* Thus the substitution is done in-place, in the sense that it modifies this Lob
* and/or its descendants. To return a modified copy instead, create the copy and
* then call freeSubstitute() in the copy.
*
* This routine is tested by test_bind::test_substitution().
*/
void freeSubstitute ( Lob var, Lob term, Lob context = Lob() );
/** \brief Whether the given term is free to substitute in place of this Lob in context
*
* A term is free to replace this Lob in context if no variable in term would become
* bound by a quantifier within context because of the substitution. Thust the
* \a context parameter here functions much as it does in several other routines in
* this class, such as freeVariables().
*
* Although this routine is intended to be used when this Lob is a variable,
* it can be used in other circumstances as well; in such cases, "substitution"
* is perhaps an inaccurate phrase, but the idea is the same: a future call to
* Lob::set() is anticipated, and its ramifications on \a term are to be determined.
*
* This routine is tested by test_bind::test_substitution().
*/
bool freeToSubstitute ( Lob term, Lob context = Lob() ) const;
/** \brief Rename all instances of a variable bound by this Lob, if it is a quantifier
*
* Assuming this Lob is a quantifier one of whose bound variables is \a var,
* then find all occurrences of \a var inside this Lob that are bound by this particular
* quantifier, and replace each one with a copy of \a newvar.
*
* Note that nested quantifications of the same variable are not changed.
* For instance, if you call this routine on Forall x Exists x P(x), to change x to y,
* you will end up with Forall y Exists x P(x), because the inner x's were not bound
* by the outer quantifier. Only instances of the variable bound by <i>this</i>
* Lob are changed.
*
* This routine is tested by test_bind::test_substitution().
*/
void renameBound ( Lob var, Lob newvar );
/** \brief Move all attributes from this Lob to another Lob
*
* This does not copy the attributes, it moves them. This Lob will no longer have the
* attributes, but \a other will.
*
* This can be useful in combination with set(), so that if you wish to replace one Lob
* with another while preserving attributes, you can proceed as follows.
* \code
* original.moveAttributesTo( replacement );
* original.set( replacement );
* \endcode
*
* If you execute the second line without the first, then the replacement takes place
* wholesale, and no attributes are preserved.
*
* This routine is not yet tested in any unit tests, except very indirectly in that it is
* used in renameBound().
*
* \see set(), renameBound()
*/
void moveAttributesTo ( Lob other );
private:
#ifdef LURCH_UNIT_TEST
friend class LURCH_UNIT_TEST;
#endif
/** Allow LobChange objects to read omobj, so they can do detailed and/or efficient edits
*/
friend class LobChange;
/** \brief The pointer to the OpenMath object for which this is a wrapper
*/
OmNode* omobj;
/** \brief Whether the Lob is editable (the opposite of read-only)
*/
bool editable;
/** A helper routine for getNewID() and changeIDs(), which finds a Lob's ID context
*/
Lob findIDContext () const;
/** A helper routine for changeIDs(), which does its first phase of work
*/
void buildIDConversion ( QString& nextID, Lob context,
QMap<QString,QString>& conversion );
/** A helper routine for resetAllIDs(), which does its second phase of work
*/
void convertIDReferences ( const QMap<QString,QString> conversion );
/** A helper routine for checkUniqueIDs() and checkUniqueNicknames()
*/
bool checkUnique ( QString nicknameOrID ) const;
/** A helper routine for removeExtraIDs(), which finds all referenced IDs
*/
void findReferencedIDs ( QStringList& result );
/** A helper routine for ensureUniqueIDs(), which removes all unreferenced IDs
*/
void removeUnreferencedIDs ( const QStringList referenced );
/** \brief A subroutine to check if two variables are equal
*
* Breaking this out into a subroutine makes it possible that later it may,
* rather than handling the comparison itself, delegate it to a script routine,
* by emitting a signal with a bool& parameter, say.
*
* This routine assumes the two given Lobs are variables, so it simply compares their
* values as variants, using toVariant().
*/
bool compareVariables ( Lob var1, Lob var2 ) const;
/** \brief Whether the variable appears on the list, according to compareVariables()
*
* This functionality is put here to factor it out of several routines that make use
* of it, including routines in this class as well as unit tests.
*
* \return true if and only if there is some element of \a list which, when converted
* to a Lob using list[i].value<Lob>(), is equal to \a var according to
* the compareVariables() method in this Lob
*
* This routine is indirectly tested by test_bind::test_all_bound().
*/
bool variableOnList ( Lob var, QVariantList list ) const;
/** \brief Merge two lists of variables, preserving uniqueness as per compareVariables()
*
* Return a new list containing all variables from both list \a a and list \a b,
* except without any duplicates, where equality is tested using the compareVariables()
* method of this Lob.
*/
QVariantList mergeVariableLists ( QVariantList a, QVariantList b ) const;
/** \brief Getter for the Lob::type property, for use in scripts
*
* This is different from the nodeType() method only in that it converts to an integer,
* so that no OmType enum is necessary in-script.
*
* \see nodeType()
*/
int scriptNodeType () const;
/** \brief Getter for the Lob::keys property, for use in scripts
*
* This is different from the attributeKeys() method only in that it converts to a
* QObjectList so that the script environment will not be confused by a QList&lt;Lob>
*
* \see attributeKeys()
*/
QVariantList scriptAttributeKeys () const;
/** \brief Inserts an attribute in the attribute list
*
* This is declared private because clients of this class have access to the
* setAttribute() method, which should be all they need. But the LobChange class
* needs to be able to guarantee indexes do not change when changes are applied,
* undone, reapplied, etc. Therefore fine control over indexing is provided here.
*
* Although LobChange could simply manipulate the underlying OpenMath tree, that
* would not give this object a chance to emit change signals correctly, which this
* method does.
*/
void insertAttribute ( uint index, QString keyName, QString keyCD, Lob value );
/** \brief Removes an attribute from the attribute list
*
* This is declared private because clients of this class have access to the
* removeAttribute() method, which should be all they need. But the LobChange class
* needs to be able to guarantee indexes do not change when changes are applied,
* undone, reapplied, etc. Therefore fine control over indexing is provided here.
*
* Although LobChange could simply manipulate the underlying OpenMath tree, that
* would not give this object a chance to emit change signals correctly, which this
* method does.
*/
void removeAttribute ( uint index );
/** \brief Convenience function to simplify fetching string properties internally
*
* Gets the given attribute and returns its value as a string, unless it is not a
* string node, in which case the empty string is returned. The XHTML escapes
* <code>&amp;nbsp;</code>, <code>&amp;quot;</code>, <code>&amp;apos;</code>,
* <code>&amp;lt;</code>, <code>&amp;gt;</code>, and <code>&amp;amp;</code> are replaced
* with their meanings (in that order).
*/
QString getStringAttribute ( QString symbolName, QString symbolCD ) const;
/** \brief Convenience function to simplify writing string properties internally
*
* Sets the given attribute to the given string value, overwriting whatever is
* currently at that place in the OmNode tree, if anything. The XHTML characters
* &amp;, &gt;, &lt;, &quot;, &apos;, and non-breaking space; are replaced with their
* escaped versions (in that order).
*/
void setStringAttribute ( QString symbolName, QString symbolCD, QString value );
/** \brief Lookup table to store reference counts for all wrapped OmNode pointers
*
* \see hold(), release()
*/
static SafeSingleton<QMap<OmNode*, unsigned long int> > referenceCounts;
/** \brief Whether the given OmNode* nor any of its descendents nor their attributes
* are wrapped by Lobs
*/
static bool descendentsUnreferenced ( OmNode* node );
/** \brief A Lob calls this when it begins wrapping an OmNode*, to add one to the
* reference count
*
* \see referenceCounts, release()
*/
static void hold ( OmNode* node );
/** \brief A Lob calls this when it stops wrapping an OmNode*, possibly triggering
* deletion
*
* A Lob calls this in exactly two situations. When it is destroyed, it releases
* the node it wraps. When it is assigned to a new Lob, and thus begins wrapping
* that Lob's OmNode*, it releases the one it formerly wrapped.
*
* If this node belongs to a tree in which no other node is wrapped by any Lob,
* then the entire tree of OmNodes is deleted. Otherwise, none is, and we wait
* until the last Lob wrapping any of them is deleted. (This way, Lobs can use
* their parent(), child(), nextSibling(), etc. functions to navigate a tree without
* fear that some of it may be deleted.)
*
* \see referenceCounts, hold()
*/
static void release ( OmNode* node );
/** \brief The list of Lobs that wish to emit the modified() signal accurately
*/
static SafeSingleton<QList<Lob*> > watchForModifications;
/** \brief Set this Lob's ID
*
* The ID is stored in the attribute whose key has name ID and content dictionary
* LurchCore.
* The attribute's value must be an OmStringNode containing "id" followed by
* a sequence of decimal digits.
* (This is distinct from the OpenMath id attribute, which is for
* OpenMath References, which are for compacting documents for storage,
* and have no actual meaning for the mathematics represented by the document.)
*
* If \a id is not of the specified form, then this function does nothing.
* (It also does nothing if the object is not editable, or an empty Lob.)
*
* The Lob class provides the public functions reference() and referent() for dealing
* with IDs; script authors only need to deal with those.
* For a detailed description of the Lurch ID System,
* see the <a href='idsystem.html'>Lurch ID System page</a>.
*
* \see getID(), reference(), referent()
*/
void setID ( QString id );
/** \brief A map from Lurch ID contexts to the highest used ID in that context
*/
static QMap<Lob,QString> highestIDs;
/** \brief Find the next ID after the largest used in this Lob's context
*
* If this Lob has a context with a cached largest ID, this will be efficient.
* If this Lob has no context, then the time this routine takes is based on how large
* of an OpenMath tree this Lob sits inside.
*
* Read more about this routine and the whole Lurch ID System on
* <a href='idsystem.html'>The Lurch ID System page</a>.
*/
QString getNewID () const;
/** A helper routine for referent(), which looks up referenced IDs recurisely
*/
Lob recursiveReferent ( QString id, OmNode* skip = NULL ) const;
/** \brief If the modification takes place below a watched Lob, have it emit modified()
*
* This routine is tested in test_change::test_recording() and
* test_lob_edit::test_read_only().
*/
void maybeEmitModified ( const LobChange& change,
OmNode::OwnershipType fromHere = OmNode::None,
unsigned int fromIndex = 0 ) const;
/** For use when this Lob is an ID context and needs to watch for changes that may
* necessitate changing its highest cached ID
*/
void updateHighestID () const;
private slots:
/** For use when this Lob is an ID context and needs to watch for changes that may
* necessitate changing its highest cached ID
*/
void updateHighestID ( const LobChange& change ) const;
};
/** \brief Tests structural equivalence of two OpenMath trees
*
* See the description of Lob::equivalentTo(); this is its implementation.
* Two different OpenMath trees that have the same nodes in the same arrangement are
* equivalent(), but are not operator==().
*
* \param a Pointer to an OpenMath node, the entire subtree under which
* will be compared to \a b
* \param b Pointer to an OpenMath node, the entire subtree under which
* will be compared to \a a
* \param compareAttributes When true, the two nodes' attributes are checked to see if they
* also match; otherwise, attributes may be different and the two
* nodes still be equivalent(). See Lob::equivalentTo() for more.
* \param exclusions Allows you to exclude certain name/CD pairs from consideration.
* See Lob::equivalentTo() for more.
*
* This routine obviously contains an implementation of comparing two OpenMath leaf nodes
* (OmFinalNode), and the following rules explain that comparison.
* <ul>
* <li>Two integer nodes are equivalent() if and only if they have the same value
* (OmIntegerNode::getValue()).</li>
* <li>Two float nodes are equivalent() if and only if they have the same value
* (OmFloatNode::getValue()).</li>
* <li>Two big integer nodes are equivalent() if and only if they meet the criteria I
* describe on \link openmath the page on OpenMath notes\endlink.</li>
* <li>Two byte array nodes are equivalent() if and only if they have the same lengths
* and each byte in one array matches the byte of the same index in the other array
* (both length and content fetched via OmByteArrayNode::getBuffer()).</li>
* <li>Two string nodes are equivalent() if and only if their buffers
* (OmStringNode::getBuffer()) match under the C <code>strcmp</code> function.</li>
* <li>Two variable nodes are equivalent() if and only if their names
* (OmVariableNode::getName()) match under the C <code>strcmp</code> function.</li>
* <li>Two processing instruction nodes are equivalent() if and only if their buffers
* (OmPInstructionNode::getBuffer()) match under the C <code>strcmp</code>
* function.</li>
* <li>Two symbol nodes are equivalent() if and only if their names
* (OmSymbolNode::getName()) match under the C <code>strcmp</code> function,
* and their content dictionaries (OmSymbolNode::getCD()) do as well.</li>
* <li>Two wide string nodes are equivalent() if and only if their buffers
* (OmWStringNode::getBuffer()), after conversion to QString objects via
* QString::fromWCharArray(), pass the <code>==</code> comparison test with one
* another (see QString::operator==()).</li>
* </ul>
* A non-final node is equivalent to another non-final node if each child of the first
* is equivalent() to the corresponding (same-indexed) child of the second.
*
* See \link openmath the page on OpenMath notes\endlink for information about how this
* routine interprets big integer objects.
*
* This class is tested by test_lob::test_equivalence(),
* test_lob::test_attributes(), and test_ref::test_exclusion().
*
* \see Lob::equivalentTo()
*/
bool equivalent ( const OmNode* a, const OmNode* b,
bool compareAttributes = false, QStringList exclusions = QStringList() );
/** \brief Deletes an OmNode
*
* No destructors in any class inheriting OmNode are public, except for OmDocument.
* Therefore you cannot create an OmNode descendant in either of the ways exemplified
* in the following block of code, because both require calling destructors, to which
* you have no access.
* \code
* void functionThatDoesNotCompile ()
* {
* OmNode example( OmIntegerType );
* OmNode* another = new OmBigIntegerNode();
* // do something
* delete another;
* }
* \endcode
* Although you can create them using new and then not delete them, this is obviously
* not what you want, because it is a memory leak. The intent is for you to create an
* OmDocument and place them in it as children. It takes ownership, and deletes its children
* when it is deleted. The following code is acceptable.
* \code
* void functionThatCompiles ()
* {
* OmDocument doc;
* doc.append( new OmIntegerNode( 5 ) );
* // do stuff, then doc deletes its children when it is deleted
* }
* \endcode
* So this routine was created to place any OmNode inside a dummy OmDocumentNode, which
* will be deleted (with its one child, the parameter) at the end of this routine's
* execution. Note that you cannot call it like this.
* \code
* void anotherNonCompilableOne ()
* {
* OmNode example( OmIntegerType );
* deleteOmNode( &example );
* }
* \endcode
* Thankfully, the compiler will not permit such shenanigans, because (not knowing that you
* have already freed the memory) it tries to do so again at the end of the routine, and
* cannot, because you can't access the destructor. Instead, write code like this.
* \code
* void theRightWay ()
* {
* OmNode* example = new OmIntegerNode( 42 );
* // do stuff
* deleteOmNode( example );
* }
* \endcode
* The only exception to this is that the parameter cannot be of type OmUnknownType,
* unless it is an OmDocumentNode object. In this latter case, the object is simply deleted
* without any wrapping needed; <b>otherwise this function takes no action</b>.
*
* This routine is untested; it seems straightforward, but testing it doesn't..
*/
void deleteOmNode ( OmNode* doomed );
/** \brief Convert OmType to QString for debugging purposes
*/
QString nameOfOmType ( OmType type );
/** \brief Escape the XML metacharacters &lt;, &gt;, &amp;, etc.
*
* This is used when putting textual data into an XML expression, such as an OpenMath
* &lt;OMSTR&gt; object. It replaces characters that would invalidate the XML with their
* appropriately escaped versions, &amp;quot;, &amp;apos;, &amp;lt;, &amp;gt;,
* &amp;amp;, and any unicode character not in Latin1.
*/
QString escapeXML ( QString notSafeForXML );
/** \brief Unescape the XML metacharacters &lt;, &gt;, &amp;, etc.
*
* Reverse the operation of escapeXML(), useful for data that comes from inside an XML
* tag and thus may have been encoded using escapeXML().
*/
QString unescapeXML ( QString escaped );
/** \brief Increments a Lurch ID string to hold an ID value one higher
*
* Read more details on <a href='idsystem.html'>The Lurch ID System page</a>.
*
* This routine is tested in test_lob::test_non_members().
*/
QString incrementID ( QString id, unsigned int index = 0 );
/** \brief Compares two ids and determines if A < B numerically
*
* Read more details on <a href='idsystem.html'>The Lurch ID System page</a>.
*
* This routine is tested in test_lob::test_non_members().
*/
bool lessThanID ( const QString& idA, const QString& idB );
/** \brief Creates a Lurch ID whose numerical value is zero
*
* Read more details on <a href='idsystem.html'>The Lurch ID System page</a>.
*
* This routine is tested in test_lob::test_non_members().
*/
QString zeroID ();
Q_DECLARE_METATYPE( Lob* )
Q_DECLARE_METATYPE( Lob )
#endif // LOB