[go: up one dir, main page]

Menu

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

Download this file

1234 lines (1133 with data), 60.5 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
#ifndef LURCH_ENVIRONMENT
#define LURCH_ENVIRONMENT
#include "lob.h"
#include "lchange.h"
#include "lobscript.h"
#include "lpathtracker.h"
class LurchPackage;
/** \brief A script interpreter, current document, and set of document search paths, plus
* the functionality for working with them together
*
* This object sets up the scripting environment in the interpeter using setupInterpreter(),
* which calls addLobsToScriptEngine().
*
* It keeps a current document which can be retrieved through document() and modified
* with any of the Lob member functions, and loaded, saved, or erased with methods in this
* class. It keeps a set of document search paths so that it can find and load dependencies
* of any document it is asked to load.
*/
class LurchEnvironment : public LurchPathTracker
{
Q_OBJECT
public:
/** \brief Construct a new Lurch Environment with no search paths
*
* Although you can leave the list of search paths empty, this is rarely desirable,
* because then no document can have dependencies, for they would never be found.
* Use the add() method inherited from LurchPathTracker to add search paths, and
* watch its return value to ensure no conflicts.
*
* This object is also indexed (using environments) at construction time.
*
* The indexing is tested in test_lenv::test_indexing().
*/
LurchEnvironment ();
/** \brief Un-indexes this object before deletion
*
* \see environments
*
* This routine is tested in test_lenv::test_indexing().
*/
~LurchEnvironment ();
/** \brief Retrieve the current document
*
* If this environment was just constructed, no calls to load() have succeeded,
* and no calls to newDocument() have been made, this will be an empty Lob.
*
* You can change the current document with any of the member functions in the Lob
* class applied to the result of this document() call, except set(), which will
* <em>not</em> replace the document with a new one, as you might think. Instead,
* call newDocument() and then make calls to document().addChild(),
* document().setAttribute(), etc.
*
* This routine is tested in test_lenv::test_doc_and_deps().
*
* See load() and newDocument() for information on how they change the current
* document.
*/
Lob document ();
/** \brief Retrieve the script engine inside this environment
*
* Note that this function should be used with caution. You receive a pointer to
* the script engine, which may be in any number of states. It is reasonable to
* do things like
* \code
* engine()->globalObject().addProperty( ... );
* \endcode
* but not necessarily reasonable to do things like
* \code
* engine()->evaluate( ... );
* \endcode
* unless you know an evaluation is not already in progress.
*
* Furthermore, deleting the script engine object would certainly cause the program
* to crash the next time the LurchEnvironment needed to access the script engine.
* Thus use the results of this function wisely.
*/
QScriptEngine* engine ();
/** \brief Tries to load the given document or package as the current document
*
* The argument \a fnOrURN can be a filename to a Lurch document on disk, or the URN of one
* in the search paths, or the URN of a Lurch package.
*
* Attempting to load a document may fail for any number of reasons,
* inability to open the file, inability to parse the file's contents,
* the URN provided does not match any in the search paths, etc.
* Success is returned as true and failure as false;
* in the event of failure, check errorMessage() for more information.
* In the event of success, check warningMessage() to see if there are any warnings
* that did not prevent document loading, but may be relevant nonetheless
* (e.g. a dependency was missing, but the document loaded anyway).
*
* In the case of success, document() will be the loaded document, and its dependencies,
* in the order in which they needed to be loaded, will be accessible (though not
* editable) via numDependencies() and dependency().
* In the case of failure, neither document() nor any dependency() will have been
* altered.
*
* If \a fnOrURN was the URN of a package, then the current document will be read-only,
* and will contain the results of LurchPackage::asDocument() called on the package object.
* Otherwise, it will be editable.
*
* If running an auto-run script in a dependency or the document itself fails, this
* routine will <i>not</i> return failure, and the document and dependencies <i>will</i>
* have completed loading. You can detect failures of auto-run scripts by listening to
* the autoRunScriptError() signal.
*
* This routine is tested in test_lenv::test_doc_and_deps() and
* test_lenv::test_packages().
*
* \see errorMessage(), warningMessage()
*/
bool load ( QString fnOrURN );
/** \brief Tries to reload the file by calling load(), assuming it has been saved recently
*
* If the document isDirty(), this sets errorMessage with error(), and
* returns false.
*
* Otherwise, it executes load() passing as parameter lastSaveFilename, and returns
* the result of the load operation. This may, in turn, raise errors with error(),
* and cause false to be returned, or it may return true on succes; see load().
*/
bool reload ();
/** \brief Tries to save the current document under the given filename
*
* This may fail for reasons such as no write access to the file or directory, etc.
* Success is returned as true and failure as false;
* in the event of failure, check errorMessage() for more information.
*
* If it succeeds and \a remember is true, then isDirty() will become false.
* You can set \a remember to false if you want Lurch to forget that it saved the file,
* in two senses. First, it will not mark the data as clean; second, it will not change the
* last save filename. This is useful when performing autosaves, which should not count as
* actual saves of the document from the user's point of view.
*
* Before saving, this routine may modify the document by removing any unused IDs,
* with removeExtraIDs(). This may modify the document. If you do not wish this to
* happen, set \a makeChanges to false. For example, when autosaving the document
* periodically for recovery in case of a crash, it is probably not good to remove IDs,
* since they may be IDs the user was still using (e.g., amidst a cut + paste operation).
*
* You may wish to use the URN/filename conversion utilities this object inherits from
* LurchPathTracker, most notably URNToFilename() and URNToNewFilename(), for determining
* a filename if you only have a URN.
*
* This routine is tested in test_lenv::test_doc_and_deps().
*
* \see errorMessage(), isDirty()
*/
bool save ( QString filename, bool remember = true, bool makeChanges = true );
/** \brief Returns the last filename under which a save took place
*
* For more details, see documentation for lastSaveFilename.
*/
QString filename () const;
/** \brief Whether the data is "dirty," meaning recent modifications are unsaved
*
* This is set to true whenever the watchDocumentChanges() slot is called.
* It is set to false whenever a load() or save() succeeds.
*
* \see setDirty()
*/
bool isDirty () const;
/** \brief Change the "dirty" flag for this document's data (unsaved modifications)
*
* A LurchEnvironment guarantees that its isDirty() method returns reliable information
* if and only if you do not call setDirty(). If you do, then you are responsible for
* whether the information in the isDirty() flag is correct from that point until the
* LurchEnvironment modifies the value again, as described in the documentation for
* isDirty().
*
* That having been said, this method can still be useful if you need to make a friendly
* amendment to a document that should not mark it dirty. For instance, if you call
* newDocument() and then immediately afterwards give the new document a sensible initial
* title, you may not want the document to count as "dirty" despite your modification.
* In such a case, <code>setDirty( false )</code> is useful.
*
* \see isDirty()
*/
void setDirty ( bool on = true );
/** \brief Remove the current document and script context, and any dependencies;
* replace them with a new one
*
* The new document will be an OmApplicationType node with one child, the symbol
* "document" in content dictionary "LurchCore," with no additional children (arguments).
* It will have attributes taken from \a urn, unless it is not a valid Lurch URN
* (Lob::isLurchURN()), in which case default values will be put in (author
* "unknown," title "New Document," version "0"). Thus in every case it will satisfy
* the requirements of Lob::isDocument().
*
* After filling this environment with a new document, this routine ensures the URN is
* unique by calling ensureURNUniqueForAuthor() with no argument.
*
* This routine is tested in test_lenv::test_doc_and_deps().
*/
void newDocument ( QString urn = QString() );
/** \brief Remove the current document and script context, and any dependencies;
* replace them with the given one
*
* If \a filename does not refer to a loadable document, then this routine
* simply calls newDocument() with an empty string. Otherwise, this routine
* functions exactly as newDocument(), except that the new document will not be
* the empty one described in that function's documentation, but will be the result
* of loading the document in \a filename.
*
* Despite having been loaded from disk, the document will not have a default save
* filename, as you would expect of a new document. This allows using the document
* as a template without danger of saving over the original.
*
* After filling this environment with a new document, this routine ensures the URN is
* unique by calling ensureURNUniqueForAuthor() with \a author as argument. You may let
* \a author be empty here (the default); see the documentation for
* ensureURNUniqueForAuthor() for how it handles empty authors.
*
* Returns true if the template was loaded successfully, or false if the template could
* not load due to some error, so that a blank document had to be loaded instead.
*/
bool newDocumentFromTemplate ( QString filename, QString author = QString() );
/** \brief Set the list of temporary dependencies
*
* A temporary dependency is one that should always be on the dependencies list in
* memory, even if individual loaded documents do not themselves require it,
* and which should <b>not</b> be added to any individual document's dependency list,
* to prevent permanent dependence of the document on the temporary dependency.
*
* This concept allows developers to run Lurch with developer-only dependencies,
* just for one session, without altering the document they're using them to debug
* or inspect.
*
* After this function records the given list for later use, it also adds every element
* of the list to the loaded dependencies for the currently loaded
* document, but does not add any that are already on the list, nor does it add these
* dependencies to the document's attributes, so that the relationship will not be saved.
*
* Note that temporary dependencies cannot have their elements referenced by nicknames.
* This is a limitation in current code, and could be solved by some extra work, but
* I don't see it as a severe limitation, since the expectation is that this would be
* used just to load developer routines for debugging, and that no permanent reference
* to a temporary dependency (e.g., using a theorem in one as a reason in a proof)
* should occur.
*
* \return True on success, false on failure. If failure, check errorMessage().
* If this function fails, it empties the list of temporary dependencies in
* memory, rather than leave an invalid list around for later failures.
*/
bool setTemporaryDependencies ( QStringList filenames );
/** \brief Get the list of temporary dependencies
*
* This function simply returns the last list passed to setTemporaryDependencies().
* See the documentation for that function to learn what a temporary dependency is.
*/
QStringList getTemporaryDependencies () const;
/** \brief How many dependencies the current document has (recursively)
*
* The order is created by reading the dependencies for the current document,
* and inserting before each one any of its dependencies, and so on recursively.
* For example, if the current document depends on two documents A and B in that order,
* and A depends on nothing, yet B depends on C and D in that order,
* then the current document has four dependencies, in the order A, C, D, B.
*
* This function returns how many there are, and you can use dependency() to look
* them up. The dependencies list is populated when load() is called.
*
* This routine is tested a bit in test_lenv::test_doc_and_deps().
*
* \see dependency()
*/
int numDependencies () const;
/** \brief Look up one of the current document's dependencies (a read-only Lob)
*
* Descriptions of how the dependencies list is populated and in what order can be
* found in load() and numDependencies(). This routine fetches one of the
* dependencies, and returns it as a read-only Lob (see Lob::isEditable()).
* If \a index is out of range (smaller than zero or greater than or equal to
* numDependencies()) then an empty Lob is returned.
*
* This routine is tested a bit in test_lenv::test_doc_and_deps().
*
* \see load(), numDependencies()
*/
Lob dependency ( int index ) const;
/** \brief Whether the given dependency is a package (as opposed to just a document)
*
* Returns true if the dependency named is a package, false if it is a document only.
* (Packages have virtual documents that appear in the dependency list, as returned
* by dependency(), hence the phrase "document only".)
* If \a index is outside the valid range (same range as for dependency()) then
* false is returned.
*
* This routine is tested in test_lenv::test_packages().
*/
bool dependencyIsPackage ( int index ) const;
/** \brief The first package instantiating the template class \a T
*
* Obviously, \a T should be some descendant of LurchPackage for this to make any sense.
* This will return the first package in the array of dependencies for the current
* document that inherits the class \a T.
*
* Example use:
* Say you're writing C++ code in one package A, which would like to check if package B
* is also loaded, and if so, make use of it. One way to do so, inside a member function
* of package A, would be as follows.
* \code
* // this assumes that the variable env was saved from the initialize() function,
* // and refers to the current LurchEnvironment
* MyPackageB* packageBInstance = qobject_cast<MyPackageB*>(
* env->loadedPackage( "MyPackageB" ) );
* if ( packageBInstance ) {
* // then the package does exist, and I have a valid instance of it,
* // in fact, the particular valid instance that's in the same LurchEnvironment
* // as the instance of MyPackageA in which this code is being run
* packageBInstance->doSomeSpecialPackageBThing();
* }
* \endcode
*/
LurchPackage* loadedPackage ( const char* className ) const;
/** \brief Look up the alias for one of the current document's dependencies
*
* By default, dependencies have no aliases, but if the dependency was specified
* not just as a basic URN, but as one with the optional <code>identifier=urn</code>
* syntax documented in Lob::isLurchURN(), then it will have the identifier as its
* alias. This has an effect of creating a namespace for that dependency in the
* LurchEnvironment's QScriptEngine.
*
* The alias for any dependency can be fetched with this function, and it returns
* an empty string if no alias was given, or the alias otherwise.
*/
QString alias ( int index ) const;
/** \brief Get the address of a Lob in the document/dependency list
*
* The LobAddress class (and supporting routines in Lob to use it) only deals with
* addresses of Lobs inside other Lobs. LurchEnvironment, however, keeps an array
* of Lobs (the document's dependencies) followed by the document itself (the one
* top-level, non-dependency Lob). It is useful to think on the level of addressing
* a Lob within an environment, where the first step answers the question "In which
* dependency (or the document itself) is the addressed Lob?"
*
* This routine returns a LobAddress whose first step is of type AsChild, with index
* between 0 and numDependencies()-1 if it is a step into a dependency, or
* numDependencies() if it s a step into the document, and whose remaining steps
* are the address within that document.
*
* This routine is tested in test_lenv::test_packages().
*/
LobAddress address ( const Lob docOrDepNode ) const;
/** \brief Get the a Lob from the document/dependency list given an extended address
*
* See address() for information about the concept of an extended address, for indexing
* into the document/dependency list.
*
* This routine takes a LobAddress whose first step is of type AsChild, with index
* between 0 and numDependencies() inclusive, as would be returned from address(),
* and it returns the corresponding Lob inside either a dependency or the document.
* That is, for any LurchEnvironment e and any Lob L in any of its dependencies or
* document, this routine looks up Lobs such that
* <code>e.index( e.address( L ) ) == L</code>.
*
* If the address does not begin with an AsChild step, or the index is not in the
* specified range, this routine returns an empty Lob. An empty Lob may also be
* returned if the address thereafter is invalid (e.g., asking for child 7 in a
* dependency with 3 children, or any other error that can come about from
* Lob::index()).
*
* This routine is tested in test_lenv::test_packages().
*/
Lob index ( const LobAddress address ) const;
/** \brief Execute the given script code in the interpreter
*
* Simply executes the given script code in the script interpreter in this object
* and returns the result as a QScriptValue. (Errors in script execution do not
* impact errorMessage(); the script value returned will be the error.)
*
* If any auto-run script in the document or any of its dependencies has been edited
* since the last evaluation of any script code in this environment, the environment
* will call scriptUpdate() to ensure it is up-to-date before running this code.
*
* If \a activationObject is nonempty, then a new context is pushed on the interpreter,
* and in its activation object each property of \a activationObject is copied over.
* When evaluation is done, the context is popped.
*
* If \a withPrevious is true, then any alterations this makes to the document will
* not be added to the undo stack as a new action, but will be combined into the
* previous action.
*
* This routine is tested a bit in test_lenv::test_modifications().
*/
QScriptValue evaluate ( QString script, QScriptValue activationObject = QScriptValue(),
bool withPrevious = false );
/** \brief If a recent operation failed, this gives the error message
*
* If the most recent operation (such as loading a document) succeeded, this routine
* returns the empty string.
*
* This routine is tested a bit in test_lenv::test_doc_and_deps().
*/
QString errorMessage () const;
/** \brief If a recent operation succeeded but with warnings, this gives the warning message
*
* If the most recent operation (such as loading a document) succeeded, but something
* happened that the user may wish to know about (e.g., some dependencies did not load),
* this routine will return the warning message. If there were no warnings, it will be
* empty.
*
* This routine is untested.
*/
QString warningMessage () const;
/** \brief This environment's unique integer index, for use in script data fields
*
* The inverse getter for the environments property; see its documentation for more
* details.
*
* This routine is tested in test_lenv::test_indexing().
*/
int index ();
/** \brief A way to retrieve the environment based on its index
*
* A getter for the environments property; see its documentation for more details.
*
* This routine is tested in test_lenv::test_indexing().
*/
static LurchEnvironment* lookupEnvironment ( int index );
/** \brief Set the current document's URN
*
* This is a necessary function even though the option exists to simply call
* <code>document().setURN()</code>. The reason is that this latter call will not
* accomplish anything, because this object watches and prevents changes to the document
* URN. This function, however, turns off such policing just for the duration of this
* one change.
*/
void setCurrentDocumentURN ( QString urn );
/** \brief Set the current document's dependency list
*
* This is a necessary function even though the option exists to simply call
* <code>document().setDependencies()</code>. The reason is that this latter call will
* not accomplish anything, because this object watches and prevents changes to the
* dependency list.
* This function, however, turns off such policing just for the duration of this
* one change.
*
* The document must (and will) be completely reloaded after
* any changes to dependencies are made. This may cause errors if a recently added
* dependency has errors in it, such as
* conflicting IDs or nicknames, or XML or script syntax problems.
*
* Returns true on success, or false on failure. If false is returned, check
* errorMessage() for details. Reasons for failure include the inability to save the
* document temporarily to disk, a necessary step in changing dependencies.
*
* Note that if this function is called with an argument equal to the document's
* current dependency list, this function does nothing (saves time).
* The exception to that rule is if the parameter is an empty list, which is useful
* for setting up the document's dependencies for the first time.
*/
bool setCurrentDocumentDependencies ( QStringList dependencies );
/** \brief Sets the given key-value pair as an attribute on the document, silently
*
* By "silently," I mean that the action will not be recorded on the undo/redo stack.
* There may occasionally be other metadata besides the URN and dependencies
* (settable with setCurrentDocumentURN() and setCurrentDocumentDependencies(),
* respectively) that may need to be stored in the document. Since the action of storing
* that metadata may be invisible to the user, it should not be stored on an undo/redo
* stack. This function is useful in that situation.
*
* Note related but different behavior is available with setActionsInvisible(). That
* function does record the actions on the undo stack, but merged with the previous
* action. This function is more like a generalization of setCurrentDocumentURN() and
* setCurrentDocumentDependencies().
*/
void setDocumentMetadata ( Lob key, Lob value );
/** \brief Convert a list of direct dependencies into a list of indirect ones also
*
* Given a list of URNs that are to be viewed as a document's direct dependencies, what
* is the corresponding list of indirect dependencies (also a list of URNs)? This
* function does that computation and returns the result. The results will not always
* be basic Lurch URNs; some may contain aliases.
*
* Returns an empty QStringList iff an error occurred (e.g., a file was unable to be
* loaded, or successfully parsed). In such cases, errorMessage() contains information.
*
* This is a somewhat expensive function to call, because all the dependencies must be
* loaded, so that we may read their dependencies, etc.
*/
QStringList directToIndirectDependencies ( const QStringList& directDeps );
/** \brief Overrides LurchPathTracker::indexedURNs(), extending it to include package URNs
*
* The idea of LurchPathTracker::indexedURNs() is to provide a list of every URN known to
* the LurchPathTracker object. A LurchEnvironment has knowledge of more URNs,
* specifically the URN for every package compiled into the application. So this
* implementation just calls that of the parent class, then adds every package URN to the
* result before returning it.
*/
QStringList indexedURNs () const;
/** \brief Whether there are any elements on the undo stack that can be invoked
*
* If actions have been performed on the document since it was last loaded or created,
* this will be true. Then you can call undo() and expect it to perform the top action
* on the stack.
*
* \see undoAvailableChanged(), undo(), undoStack
*/
bool undoAvailable () const;
/** \brief Whether there are any elements on the redo stack that can be invoked
*
* If actions have been undone on the document recently, with no intervening changes to
* the document of any other kind, then this will be true.
* Then you can call redo() and expect it to perform the top action on the stack.
*
* \see redoAvailableChanged(), redo(), redoStack
*/
bool redoAvailable () const;
/** \brief If the currently loaded document is a package, return it; otherwise return null
*/
LurchPackage* documentPackage ();
/** \brief Turn on/off the treating of all document changes as "invisible" to undo/redo
*
* By default, any change that takes place in the document is treated as an action and
* placed on the undo stack, so that it can be undone. This is often desirable, because
* each of the user's edits changes the document, and thus immediate undo/redo support
* is present, at this foundational level.
*
* However, sometimes this behavior is undesirable. For example, when a background
* process tweaks the contents of the document periodically, without the user's knowledge,
* it can be confusing or even wrong to give the user the ability to undo/redo those
* changes. What should happen instead is that any such changes invisible to the user
* are automatically merged with the user's previous action. Although they happened at
* different points in time, they are logically united as consequences of the same
* action on the part of the user.
*
* This function supports that functionality by allowing any other code that is about to
* modify the document outside of the user's initiative to turn on/off "invisible" mode.
* Actions that happen without the user's initiative are said to be "invisible" to him
* or her, and thus when invisible mode is turned on in the environment, all document
* changes are merged with the previous item on the undo stack (iff there is one).
* Thus a process that modifies the document outside without the user's specifically
* having initiated the action should proceed as follows.
* \code
* // LE is an object of type LurchEnvironment
* LE.setActionsInvisible( true );
* performLotsOfChangesInHere( LE );
* LE.setActionsInvisible( false );
* \endcode
* Please ensure calls to this function come in matched pairs, as shown above!
*/
void setActionsInvisible ( bool on = true );
/** \brief Returns whether actions are currently invisible or not
*
* \see setActionsInvisible()
*/
bool getActionsInvisible () const;
/** \brief Set the environment in a "busy" state, so that other tasks know to wait
*
* This class does not respect the "busy" state in any of its own actions, but other
* tasks that manipulate the document or the script environment may share this datum.
* If one such task is about to perform a large-scale document edit, and does not
* want another task to interrupt it and begin other work until the large task is
* complete, it can call setBusy() to true. If all tasks that periodically interrupt
* others first check isBusy() before proceeding, this helps with performance and
* responsiveness of the application.
*/
void setBusy ( bool on = true );
/** \brief Queries the most recent value set with setBusy()
*
* See that function's documentation for more information.
* The "busy" value begins in the false state when this object is created.
*/
bool isBusy () const;
public slots:
/** \brief Undo the last document change
*
* Applies the action on the top of the undo stack.
* This will only have an effect if changes have been made since the document was
* loaded or created.
*
* \see undoAvailable(), undoStack
*/
void undo ();
/** \brief Redo the last undone action
*
* Applies the action on the top of the redo stack.
* This will only have an effect if an action was just undone,
* and no document changes have happened since.
*
* \see redoAvailable(), redoStack
*/
void redo ();
private slots:
/** \brief Updates the script environment according to document changes
*
* This slot is designed to be triggered by the Lob::modified() signal in the current
* document. The LurchEnvironment constructor sets up the connection.
* This function serves several purposes.
*
* <ol>
* <li>If the change modified the author, version, title, or dependencies of the
* document, change them back and set an error message stating that the
* document's URN and dependencies are not directly modifiable.
* This prevents scripts from modifying them; C++ clients of this class
* may call setCurrentDocumentURN() and setCurrentDocumentDependencies().</li>
* <li>If new data was inserted, check to see if it introduced any nickname
* conflicts. If so, undo the change and give an appropriate error message.
* Otherwise, add the new data's nickname information to the nickname lookup
* table.</li>
* <li>If old data was removed, remove it's nickname information from the nickname
* lookup table.</li>
* <li>Set the document dirty flag to true.</li>
* <li>If the change involved an auto-run script, set the script environment dirty
* flag to true.</li>
* <li>Clear the error message, to indicate success.</li>
* </ol>
*
* This routine is tested a bit in test_lenv::test_modifications().
*/
void watchDocumentChanges ( const LobChange& change );
/** \brief Posts the accumulated changes to the undo stack and clears out \a scriptAction
*
* See noteChange() and scriptAction for more information.
*/
void changesEnded ();
signals:
/** \brief A signal propagated from the inner document Lob
*
* See Lob::modified() for more information on the signal itself, and its parameter.
*
* Note that this document watches the Lob::modified() signal emitted from the
* document() object, and if it is an impermissible change (as described in the
* watchDocumentChanges() signal handler), it reverses it and never emits this
* signal to the outside. All other times, the document's modified signal is simply
* passed on unchanged.
*/
void documentModified ( const LobChange& change );
/** \brief Same as documentModified(), but emitted last
*
* Qt signals and slots have no defined order in which they are fired. However, in Lurch,
* Lob-to-WP syncing needs to be the last to handle any documentModified() signals. The
* reason for this is that it sometimes changes the document further, which emits more
* documentModified() signals. If that happened before all other signals had heard the
* first ones, they would be received in the wrong order, and therefore be inconsistent
* with the document itself.
*
* Thus we provide this special signal for just that purpose. It is emitted immediately
* after any documentModified() signal, with the same data. If the slot to which it is
* connected modifies the document, then further documentModified() and then
* lateDocumentModified() signals will be emitted for those changes, of course.
*/
void lateDocumentModified ( const LobChange& change );
/** \brief Emitted when a new QScriptEngine has been created/refreshed within this object
*
* Occasionally this object needs to create and destroy its internal QScriptEngine
* \a interp, when loading a new document or refreshing the script environment, etc.
* This signal lets the outside world know that such events have taken place, in case
* they have modifications to make to the interpreter, such as adding functionality.
*/
void newScriptEngine ( QScriptEngine* engine );
/** \brief Emitted when an auto-run script aborts with an error
*
* Whenever changes to auto-run scripts take place, the environment notices, and marks
* the script engine dirty. This will trigger a complete destruction and recreation of
* the script engine, together with a full re-running of all auto-run scripts in the
* document and dependencies before the next evaluation of any script code in that engine.
* Because of this (and that recreations of the scripting environment also happen at other
* times) there are many points at which an auto-run script error could occur. Thus the
* simplest solution is to emit a signal when that occurs. This is that signal.
*
* The \a message argument contains the error in human-readable form.
* This includes a mention of the fact that because one auto-run script had an error,
* subsequent auto-run scripts were not executed, and thus some functionality and/or
* data may be missing from the script environment.
*/
void autoRunScriptError ( QString message );
/** \brief Emitted when the status of undo action availability changes
*
* \param yesno true if and only if an action has been done that can now be undone
*
* \see undoAvailable()
*/
void undoAvailableChanged ( bool yesno );
/** \brief Emitted when the status of redo action availability changes
*
* \param yesno true if and only if an action has been undone that can now be redone
*
* \see redoAvailable()
*/
void redoAvailableChanged ( bool yesno );
/** \brief Emitted when a script function wants to communicate with the user interface
*
* A LurchEnvironment does not come with a user interface, and so it provides a function
* called <code>UI()</code>, in script, by which scripts can request that the environment
* emit this signal.
*
* If no user interface is in place (e.g., in simple_script) then this
* signal will not be heard and no effect will take place. The \a result parameter will
* remain in its initial, unchanged (undefined/invalid) condition, so that the script's
* call to <code>UI()</code> will be as if it had not contained a "return" statement.
*
* If a user interface is in place, listening for this signal, then it can handle the
* function call and modify the \a result parameter to return a value.
*
* Those user interfaces that listen to this signal should interpret the first argument
* in the context as a string indicating the action to take. It is suggested that user
* interfaces at least implement the following actions:
* <ul>
* <li><b>provides</b>, as in <code>UI( "provides", "foo" )</code>:
* returns a boolean, true if and only if the user interface provides a command
* called foo, so that later calls to <code>UI( "foo", ... )</code> will be
* obeyed</li>
* <li><b>alert</b>, as in <code>UI( "alert", "message" )</code>:
* display a message to the user, like the typical Javascript alert function</li>
* </ul>
*/
void userInterfaceCall ( QScriptContext* context, QScriptEngine* engine,
QScriptValue& result );
/** \brief Emitted when a package emits the signal of the same signature
*
* This signal is just here to pass along signals emitted by packages to any potentially
* listening user interface. It is similar to
*/
void packageMessageToInterface ( QString message );
/** \brief Emitted when the document's "dirty" status changes
*
* If changes in the document is saved, its status will go from dirty to not dirty.
* If a document with no changes since the last save is then changed, its status will go
* from not dirty to dirty.
* When either of these happens, this signal is emitted, with the new dirty status.
*/
void dirtyChanged ( bool toThis );
private:
#ifdef LURCH_UNIT_TEST
friend class LURCH_UNIT_TEST;
#endif
friend QScriptValue nicknameLookup ( QScriptContext* context, QScriptEngine* engine );
friend QScriptValue uiCall ( QScriptContext* context, QScriptEngine* engine );
/** \brief Holds the current document; may be empty if no document loaded
*/
Lob doc;
/** \brief Whether the document has been modified since its last save
*/
bool dirty;
/** \brief Whether auto-run scripts in the document have been modified since the last
* invocation of a script
*/
bool envDirty;
/** \brief The interpreter this environment uses on functions in the document, when needed
*/
QScriptEngine* interp;
/** \brief List of dependencies on which the current document relies, in the order loaded
*
* Each Lob in this list will be read-only (!isEditable()).
*/
QList<Lob> deps;
/** \brief List of aliases for each dependency
*
* If a dependency was specified by an URN with the optional <code>identifier=urn</code>
* syntax, its alias is that identifier. If not, its alias is empty.
*/
QStringList aliases;
/** \brief List of temporary dependencies to use for this environment
*
* For an explanation of temporary dependencies, see the documentation of the
* setTemporaryDependencies() function.
*/
QStringList tempdeps;
/** \brief If a recent operation failed, the error message is stored here
*
* \see errorMessage(), error(), noErrors()
*/
QString err;
/** \brief If a recent operation succeeded, but with a warning, the message is stored here
*
* This is a counterpart to the err member.
*
* \see warning(), warningMessage(), errorMessage(), error(), noErrors(), err
*/
QString war;
/** \brief Filename into which the document was most recently saved
*
* This may be empty if the document has never been saved, and it will often be equal
* to <code>URNToFilename( document().getURN() )</code>, but it is updated internally
* every time <code>dirty</code> is set to false.
*/
QString lastSaveFilename;
/** \brief Whether to merge the next set of changes with the previous on the undo stack
*
* This is respected (and cleared) by the changesEnded() slot, which does all posting
* to the undo stack, by virtue of its being the only function that calls actionDone().
*/
bool undoMerge;
/** \brief Ensures the document's URN is unique for \a author, and remove template flags
*
* This is useful after a new document has been created, either by calling newDocument()
* or newDocumentFromTemplate(). Call this routine with the appropriate author (or none
* to keep the same author, such as the one specified in the URN passed to newDocument()),
* and the environment will perform two useful steps.
* <ol>
* <li>It will append #1, or #2, or whatever number is needed to the title, to ensure
* the URN is unique among those in the search paths. The smallest available
* number will be used.</li>
* <li>It will remove any attributes that flag the document as a topic, so that if you
* just called newDocumentFromTemplate() with a topic template, the document the
* user then creates will not be misclassified as a topic itself.</li>
* </ol>
*/
void ensureURNUniqueForAuthor ( QString author = QString() );
/** \brief Load the temporary dependencies into memory without altering the document
*
* Used by setTemporaryDependencies() and other functions to load temporary dependencies
* into memory, as described in the documentation for that function. Note that this can
* be done to a brand new, empty document, or to an existing, already-loaded document
* with its own dependencies, and it shouldn't interfere.
*
* Note that a call to this function will never return false for failure, unless the
* list of temporary dependencies has just been changed. The reason for this is that
* if setTemporaryDependencies() finds an error when trying to load the temporary
* dependencies just set, it empties the list of temporary dependencies.
*/
bool loadTemporaryDependencies ();
/** \brief Sets the error message to \a message and returns false
*
* Just a convenience, so that functions in this class and its descendants
* can write code like this.
* <pre>
* if ( something_wrong )
* return error( "Description of problem" );
* </pre>
* Or to propagate the existing error message up, this code.
* <pre>
* if ( !other_member_function() )
* return error();
* </pre>
*
* \see noErrors()
*/
bool error ( QString message = QString() );
/** \brief Counterpart to error(), returns true and sets error message to empty
*
* \see error()
*/
bool noErrors ();
/** \brief Appends \a message to the warning message and returns true
*
* Just a convenience, so that functions in this class and its descendants
* can write code like this.
* <pre>
* if ( something_slightly_wrong )
* return warning( "This operation succeeded, but you should know: ..." );
* </pre>
* If the warning message is nonempty, this first appents a newline before \a message.
*
* \see clearWarning()
*/
bool warning ( QString message = QString() );
/** \brief Counterpart to warning(), sets the warning message to empty
*
* Should be called before the beginning of an operation that may result in warnings.
*
* \see warning()
*/
void clearWarning ();
/** Stores current document's URN; this class can ensure it doesn't change unexpectedly
* using this basis for comparison.
*/
QString currentDocumentURN;
/** Stores current document's dependency list;
* this class can ensure it doesn't change unexpectedly using this basis for comparison.
*/
QStringList currentDocumentDependencies;
/** List of states in which the watchDocumentChanges() signal handler can be operating.
*
* <ul>
* <li><code>PreventChanges</code> is the default; it means to prevent changes to the
* document's URN or depdencies. That is, the moment they occur, they are
* immediately undone without the documentModified() signal ever being emitted.</li>
* <li><code>InversionInProgress</code> is a temporary state used internally for the instant
* in which the changes prevented by <code>PreventChanges</code> are undone, so that
* we do not go into infinite regress, undoing the undoing, and so on.</li>
* <li><code>AllowChanges</code> is a temporary state used internally by the routines
* setCurrentDocumentURN() and setCurrentDocumentDependencies(), to prevent their
* effects from being undone, as they would be in a <code>PreventChanges</code>
* state.</li>
* <li><code>UndoOrRedo</code> is a temporary state used internally by the routines
* undo(), redo(), and setDocumentMetadata() to prevent their effects from being
* recorded on the undo stack.</li>
* </ul>
*
* \see watchState
*/
typedef enum { PreventChanges, AllowChanges, InversionInProgress, UndoOrRedo } watchType;
/** Used for ensuring that the watchDocumentChanges() signal handler does its work
* correctly, watching only when it should, and propagating signals only when it should.
* \see setCurrentDocumentURN(), setCurrentDocumentDependencies()
*/
watchType watchState;
/** \brief The \a doc field in this object (a Lob) changed, and needs processing
*
* Specifically, that processing means calling prepareModifiedSignal() in the Lob
* and storing its URN and dependencies so that we can ensure that no later modifications
* change them.
*/
void prepareNewDocument ();
/** \brief Tries to load a document or package (with all dependencies), building a list of Lobs
*
* The argument \a fnOrURN can be a filename of a Lurch document on disk, or the URN of a
* Lurch document in the search paths, or of a LurchPackage. This routine behaves differently
* with filenames and URNs.
* <ul>
* <li>
* If \a fnOrURN is a valid Lurch URN (see Lob::isLurchURN()), this routine behaves
* as follows.
*
* If \a URN has already been loaded, this routine does nothing.
*
* If \a URN refers to a package, this loads it analogously to how it loads files (see
* below), and recurs on the URNs of the package's dependencies, as expressed
* in the Lob::dependencies() array of the LurchPackage::asDocument() Lob.
*
* If \a URN refers to a document, this converts it to a filename and recurs on it,
* thereby taking the path of the second bullet point, below.
* </li>
* <li>
* However, if \a fnOrURN is not a valid Lurch URN, this routine assumes that it is
* a filename, and behaves as follows.
*
* Recursively loads all dependencies, placing them in \a results parameter
* in the order they should subsequently be processed (i.e., dependencies come before
* the document that depends on them). Does not set the editable property of any Lob.
*
* Handles errors and return value much like load(). In the event where
* false is returned (failure), some documents may still have been loaded, and the
* results array may be nonempty. Yet neither the current document nor the current
* list of dependencies in this object will have been altered.
*
* Be aware that if two different dependencies each depend on the same third depdency,
* and each gives it a different alias, then the first dependecy loaded is the one
* whose alias will be respected, and the latter dependency may then not find its
* dependency in the namespace it expects.
* </li>
* </ul>
*/
bool recursiveLoad ( QString fnOrURN, QList<Lob>& results, QString alias,
QStringList& URNsDoneOrPending, QStringList& URNaliases );
/** \brief Construct a fresh interp, with functions for accessing parts of the environment
*
* This function constructs a new interpreter (disposing of the old one first if there
* was one), then calls addLobsToScriptEngine(), and on top of the general setup
* done there, it adds several other global functions for accessing aspects of the
* environment (this object).
*
* Specifically, these values are made available in the script environment:
* <ul>
* <li><b>document()</b> - a function that returns the environment's current document.
* Just a simple exposing of LurchEnvironment::document() to scripts.
* The result is a Lob, and it is editable.</li>
* <li><b>numDependencies()</b> - a function that returns the number of dependencies
* of the environment's current document (all of which are loaded, and accessible
* as Lobs; see the following function). Just a simple exposing of
* LurchEnvironment::numDependencies() to scripts.</li>
* <li><b>dependency( n )</b> - a function that returns dependency number <i>n</i>,
* just a simple exposing of LurchEnvironment::dependency() to scripts.
* The result is a Lob, and it is <i>not</i> editable.</li>
* <li><b>alias( n )</b> - a function that returns the string alias for dependency
* number <i>n</i>, assuming that it is a package that was imported with an alias.
* Just a simple exposing of LurchEnvironment::alias() to scripts.
* If it was not, the empty string is returned.</li>
* <li><b>lookupNickname( name )</b> - a function that searches for a Lob with the
* given nickname (in the sense of Lob::nickname()) and returns it, if one exists
* in the current document or one of its dependencies. Otherwise, an empty Lob
* is returned.
* Just a simple exposing of LurchEnvironment::lookupNickname() to scripts.</li>
* <li><b>uiCommand( cmd, ... )</b> - a function that emits the userInterfaceCall()
* signal with all its arguments. User interfaces that allow a user to interact
* with a LurchEnvironment should listen to this signal and react to those commands
* which they understand. See \link uiprotocol the Protocol for Document-UI
* Communication\endlink for more information.</li>
* </ul>
*
* This function does nothing if the current interpreter is running, because destroying it
* could cause a crash. Before calling this function, verify that the current interpreter
* satisfies !isEvaluating(). If it doesn't, then wait until it finishes.
*/
void newInterpreter ();
/** \brief Runs all "auto-run" type scripts in the given document
*
* Recursively proceeds through every attribute and child of the given Lob and runs
* the Lob::scriptCode() of any node satisfying Lob::isScript() and whose
* Lob::scriptType() is "auto-run".
*
* If \a space is nonempty, then any scripts found are evaluated in that namespace,
* using evaluateInNamespace() defined in lobscript.h.
*
* \return True if no script errors occurred, false otherwise.
* If false, check errorMessage() for details.
*/
bool autoRunScripts ( const Lob doc, QString space = QString() );
/** \brief Refresh the interpreter with a new one and run all scripts in dependencies and
* the document
*
* This function first creates an entirely new interpreter, then walks through the
* dependencies in order doing the following. If the dependency is a package, it calls
* its LurchPackage::setup() routine; whether or not it is a package, it then calls
* autoRunScripts() on it as a document. If at any point in those steps an error occurs,
* emit autoRunScriptError() and return immediately without any further processing. If
* no auto-run scripts cause errors in the dependencies, it then calls autoRunScripts()
* on the document itself and handles errors in the same way as with dependencies (emit
* signal and return).
*
* This routine is guaranteed to be called by the environment in between any edits to an
* auto-run script and any execution of other script code, so that the interpreter is
* up-to-date, as if the document had just been loaded in its latest state.
*/
void scriptUpdate ();
/** \brief A map from integers to all Lurch Environments
*
* This allows us to tell script functions which environment they belong in by a simple
* integer index, rather than trying to convert memory addresses into script values.
* See the use of this map in LurchEnvironment(), ~LurchEnvironment(), and
* setupInterpreter().
*
* This array is tested in test_lenv::test_indexing().
*/
static QList<LurchEnvironment*> environments;
/** \brief A map from nicknames to the Lobs which they name
*
* This enables fast nickname lookups. It is created by addToNicknameMap() and kept
* up-to-date by that same routine, togethr with removeFromNicknameMap(), which are
* called from watchDocumentChanges().
*/
QMap<QString,Lob> nicknameToLob;
/** \brief Adds nicknames in the given Lob to the internal map nicknameToLob
*
* This is useful when a new Lob is inserted into the document. This keeps the
* nicknameToLob map up-to-date with the nickname(s) of that Lob and its whole
* subtree. Note that this performs its operation blindly; you should first
* call safeToAddNicknames() before calling this function, to be sure you do not
* overwrite/invalidate data in nicknameToLob.
*/
void addToNicknameMap ( Lob thisTree );
/** \brief Removes nicknames in the given Lob from the internal map nicknameToLob
*
* This is useful when a Lob is removed from the document. This keeps the
* nicknameToLob map up-to-date by dropping the nickname(s) of that Lob and its whole
* subtree.
*/
void removeFromNicknameMap ( Lob thisTree );
/** \brief Finds all potential conflicts with adding the nicknames in the given Lob
*
* If any node in the given Lob's subtree is nicknamed with a name that already appears
* in nicknameToLob, then there would be a conflict with introducing the given Lob's
* tree to the existing document structure. This function checks for such conflicts.
*
* \return An empty list if no conflicts; a list of conflicts if there are any.
* Conflicts may show up on the list more than once if the given Lob has
* conflicts within itself.
*/
QStringList safeToAddNicknames ( Lob thisTree ) const;
/** \brief Looks up a nickname and returns the corresponding Lob, if any
*
* Simply performs a lookup in nicknameToLob, which returns an empty Lob if the given
* nickname is not a key in that map. Refer to the documentation for that field
* for more details.
*/
Lob lookupNickname ( QString nickname ) const;
/** This object is used internally when scripts perform multiple document changes
* at a time. They are accumulated in this object, which gets put on the undo stack.
*/
LobChange scriptAction;
/** Whether the actions taken in the document should be invisible to the user, in the sense
* that they do not take up their own slots on the undo stack, but rather merge with the
* last one. See setInvisibleActions().
*/
bool invisibleActions;
/** \brief Tell the undo/redo recording features about a change to the document
*
* This saves the initial change to the internal LobChange object \a scriptAction,
* using the same composing feature that LobChange::recordStep() uses. It also sets
* up a timer to call changesEnded() the moment the event loop resumes,
* to post the cumulative action to the undo stack.
*/
void noteChange ( LobChange initialChange = LobChange() );
/** This holds the undo stack for the currently loaded document.
* For more information, see the following routines.
*
* \see redoStack, undo(), undoAvailable()
*/
QStack<LobChange> undoStack;
/** This holds the redo stack for the currently loaded document.
* It will only ever be populated if some undo actions have been performed.
* For more information, see the following routines.
*
* \see undoStack, redo(), redoAvailable()
*/
QStack<LobChange> redoStack;
/** Places the given action on the undo stack for later undoing.
* Emits the undoAvailableChanged() signal if needed.
* See evaluate() for information on the \a withPrevious parameter.
*/
void actionDone ( const LobChange& change, bool withPrevious = false );
/** Places the given action on the redo stack for later redoing.
* Emits the redoAvailableChanged() signal if needed.
*/
void actionUndone ( const LobChange& change );
/** Track what packages I have created instances of, based on their URNs
*/
QMap<QString,LurchPackage*> urn2pkg;
/** Track what packages are dependencies of the currently loaded document
*/
QList<LurchPackage*> activePackages;
/** Look up a package in the cache of previously created ones, or create a new instance
*/
LurchPackage* getPackage ( QString urn );
/** Number of files actually loaded as a result of loading temporary dependencies
*
* This may, of course, be different than the number of filenames returned by
* getTemporaryDependencies(). It may also fluctuate as different documents are loaded
* and saved, because their dependencies impact which indirect temporary dependencies
* need to be loaded.
*/
int numTempDepsLoaded;
/** Whether the current document's title was auto-generated by this object
*
* If so, then when the document is saved, the temporary title will be replaced by the
* filename under which to save the document. This is what users expect; the filename is
* in some sense the document title. They do not expect to have an unknown,
* auto-generated title instead.
*
* This value is set to true when titles are auto-generated, and set to false when the
* document URN is replaced by something given from outside this object.
*/
bool titleWasAutoGenerated;
/** Whether some large operation is happening on the document, and other tasks should wait
*
* \see setBusy() and isBusy()
*/
bool busy;
};
#endif // LURCH_ENVIRONMENT