deps;
/** \brief List of aliases for each dependency
*
* If a dependency was specified by an URN with the optional identifier=urn
* 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 URNToFilename( document().getURN() ), but it is updated internally
* every time dirty 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.
*
* - 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.
* - 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.
*
*/
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.
*
* if ( something_wrong )
* return error( "Description of problem" );
*
* Or to propagate the existing error message up, this code.
*
* if ( !other_member_function() )
* return error();
*
*
* \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.
*
* if ( something_slightly_wrong )
* return warning( "This operation succeeded, but you should know: ..." );
*
* 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.
*
*
* PreventChanges 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.
* InversionInProgress is a temporary state used internally for the instant
* in which the changes prevented by PreventChanges are undone, so that
* we do not go into infinite regress, undoing the undoing, and so on.
* AllowChanges 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 PreventChanges
* state.
* UndoOrRedo is a temporary state used internally by the routines
* undo(), redo(), and setDocumentMetadata() to prevent their effects from being
* recorded on the undo stack.
*
*
* \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.
*
* -
* 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.
*
* -
* 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.
*
*
*/
bool recursiveLoad ( QString fnOrURN, QList& 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:
*
* - document() - 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.
* - numDependencies() - 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.
* - dependency( n ) - a function that returns dependency number n,
* just a simple exposing of LurchEnvironment::dependency() to scripts.
* The result is a Lob, and it is not editable.
* - alias( n ) - a function that returns the string alias for dependency
* number n, 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.
* - lookupNickname( name ) - 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.
* - uiCommand( cmd, ... ) - 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.
*
*
* 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 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 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 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 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 urn2pkg;
/** Track what packages are dependencies of the currently loaded document
*/
QList 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