/** \file qtextdocumentscript.h
*
* \brief Functions for adding to a script engine the API for dealing with word processing Lobs
*
* The LurchDocumentConverter class helps keep a QTextDocument (such as one in a visual editor)
* in sync with a Lob structure behind the scenes. This makes the word processing interface to
* Lurch documents possible, but also necessitates a certain structure to the Lobs that store the
* document; they must have the structure appropriate for syncing back and forth with the
* QTextDocument.
*
* This file contains routines that can add to a Qt Javascript environment an API for dealing
* with Lobs that encode the text fragments, paragraphs, and frames of a QTextDocument, together
* with their various character, paragraph, and list formatting codes. This way scripts in a
* LurchEnvironment can manipulate the document in ways that are easier to understand and that
* preserve the necessary structures.
*
* Cursor placement routines are also provided, as well as routines for converting Lob word
* processing structures to and from both HTML and plain text.
*
* The main routine defined herein is addLobTextToScriptEngine().
* Much of it is simply exposing routines and data that already exit in the Qt toolkit
* to Javascript. To have this routine called on a LurchEnvironment whenever it refreshes its
* interpreter, see the KeepLobTextAdded class.
*/
#ifndef QTEXTDOCUMENTSCRIPT_H
#define QTEXTDOCUMENTSCRIPT_H
#include <QtScript>
#include "lob.h"
/** \brief Adds to the given script engine all the API for dealing with Lobs as word processor text
*
* This routine assumes that Lobs have already been added to the script engine, using
* addLobsToScriptEngine() as documented in lobscript.h. If that is not so, this function will
* detect their absence, and finish without adding anything to the script engine. This is because
* most of what this function adds to the script engine it puts in the Lob prototype, and if that
* has not yet been defined, this routine has nowhere to put most of its routines and data.
*
* <h3>Global functions defined</h3>
* <ul>
* <li><tt>text(arg1,arg2,...)</tt> converts each argument into a string, replaces
* all newline characters with spaces, and joins them into one string with
* spaces in between. The result is then converted into a string Lob and
* returned, ready for placement in a paragraph. If zero or one arguments
* are passed, the empty Lob is returned, because word processor text fragments
* may not be empty.</li>
* <li><tt>paragraph(arg1,arg2,...)</tt> creates paragraphs for use in word
* processing structures. Each argument that is not already a text Lob (that
* is, passes the isText() test) is converted to one using the text() function.
* Then the resulting Lobs are made children to a new paragraph Lob, which is
* returned.</li>
* <li><tt>frame(arg1,arg2,...)</tt> creates frames for use in word processing
* structures. Each argument that is not already a paragraph Lob (that is,
* passes the isParagraph() test) is converted to one as if it had been passed
* to the paragraph() function.
* Then the resulting Lobs are made children to a new frame Lob,
* which is returned.</li>
* <li><tt>table(arg1,arg2,...)</tt> functions exactly like frame(), but the new
* frame returned is a table frame, rather than a standard one. This is still
* rather useless because functions have not been provided (yet) for setting the
* table structure (number of rows and columns, etc.).</li>
* <li><tt>fromPlainText('...text...')</tt> returns an array of Lobs representing
* one or more paragraphs constructed from the given text. Newlines in the
* text are interpreted as paragraph breaks.<br>
* <li><tt>fromHTML('...HTML code...')</tt> returns an array of Lobs representing
* one or more paragraphs and/or frames constructed from the given HTML.<br>
* See Qt's <a href='http://doc.qt.nokia.com/latest/richtext-html-subset.html'
* >supported HTML subset</a> to know what you can include.</li>
* </ul>
*
* <h3>Additions to the Lob prototype</h3>
* <ul>
* <li><tt>myLob.isText()</tt> returns whether <tt>myLob</tt> is a word
* processing Lob representing a text fragment inside a paragraph.
* The decision procedure is imperfect: any
* OpenMath string Lob might be a fragment of word processor text. Thus this
* check is simply a convenient renaming of the test for whether the Lob's
* type is <tt>OMTypes.String</tt>.</li>
* <li><tt>myLob.isParagraph()</tt> returns whether <tt>myLob</tt> is a word
* processing Lob representing a paragraph.</li>
* <li><tt>myLob.isFrame()</tt> returns whether <tt>myLob</tt> is a word
* processing Lob representing a frame. Frames are structures that contain
* paragraphs; they can be of a generic type (like an HTML DIV) or a specific
* type such as a table. Right now there are no functions available for
* manipulating frame-specific properties, such as their formatting or their
* layout or the rows and columns of a table. They are just plain DIV-like
* things for now.</li>
* <li><tt>myLob.isListItem()</tt> returns whether <tt>myLob</tt> is a word
* processing Lob representing a paragraph that has been formatted as part of a list.
* Lists can be of a variety of formats.</li>
* <li><tt>myLob.paragraph()</tt> returns the paragraph containing <tt>myLob</tt>,
* if there is one. If not, an empty Lob is returned. If <tt>myLob</tt> is
* itself a paragraph, then it is returned.</li>
* <li><tt>myLob.nextParagraph()</tt> returns the paragraph immediately following
* <tt>myLob</tt>, if there is one in the context in which <tt>myLob</tt> sits.
* If there is no such Lob, an empty Lob is returned. If <tt>myLob</tt> is not
* itself a paragraph, but instead contains paragraphs, this routine will yield
* the first contained paragraph.</li>
* <li><tt>myLob.previousParagraph()</tt> returns the paragraph immediately before
* <tt>myLob</tt>, if there is one in the context in which <tt>myLob</tt> sits.
* If there is no such Lob, an empty Lob is returned. If <tt>myLob</tt> is not
* itself a paragraph, but instead is contained in one, this routine will yield
* that containing paragraph.</li>
* <li><tt>myLob.frame()</tt> returns the frame containing <tt>myLob</tt>,
* if there is one. If not, an empty Lob is returned. If <tt>myLob</tt> is
* itself a frame, it will not be returned, but rather the nearest containing
* frame will be, if any.</li>
* <li><tt>myLob.setCharacterFormat(key,value)</tt> sets an aspect of the character
* format of <tt>myLob</tt>, but only if it passes the <tt>isParagraph()</tt>
* or <tt>isText()</tt> test. Acceptable keys are those that appear in the
* following examples.<br>
* Make the text a hyperlink as follows (empty URL to remove the link):<br>
* <tt>myLob.setCharacterFormat('href','http://www.example.com')</tt><br>
* Change the font family as follows:<br>
* <tt>myLob.setCharacterFormat('family','Courier New')</tt><br>
* Change the font point size as follows:<br>
* <tt>myLob.setCharacterFormat('size',12.0)</tt><br>
* Set the foreground or background style as follows:<br>
* <tt>myLob.setCharacterFormat('fg style',Formats.SolidPattern)</tt><br>
* <tt>myLob.setCharacterFormat('bg style',Formats.CrossPattern)</tt><br>
* Set the foreground or background color as follows:<br>
* <tt>myLob.setCharacterFormat('fg color','\#ff007f')</tt><br>
* <tt>myLob.setCharacterFormat('bg color','\#000000')</tt><br>
* Note!! When setting a color, first ensure that the style has been set to
* something other than Formats.NoBrush, or your color settings will have no
* effect.<br>
* Set the bold, italic, and underline as follows:<br>
* <tt>myLob.setCharacterFormat('weight',Formats.BoldWeight)</tt><br>
* <tt>myLob.setCharacterFormat('italic',true)</tt><br>
* <tt>myLob.setCharacterFormat('underline',false)</tt></li>
* <li><tt>myLob.characterFormat(key)</tt> returns the current value for the given
* key. For a list of keys and what they mean, see immediately above.
* Note that some return values may be integers that need to be compared against values
* in the Formats data structure, described below. Furthermore,
* some may not be set at all, and thus return default values when queried.</li>
* <li>The above two functions can also be used without the "key" parameter. That is, you
* can lift a character format out of one Lob using <tt>myLob.characterFormat()</tt> and
* then apply it to another Lob using <tt>myLob.setCharacterFormat(value)</tt>. (The
* value is a string that encodes all the formatting data; its format was not designed
* for reading/editing.)</li>
* <li><tt>myLob.setParagraphFormat(key,value)</tt> sets an aspect of the paragraph
* format of <tt>myLob</tt>, but only if it passes the <tt>isParagraph()</tt>
* test. Acceptable keys are those that appear in the
* following examples.<br>
* Indent the paragraph as follows (zero for no indent, no negatives):<br>
* <tt>myLob.setParagraphFormat('indent',3)</tt>
* (Note that changing the indent to zero will make a paragraph no longer a
* list item.)<br>
* Change the paragraph's alignment as follows:<br>
* <tt>myLob.setParagraphFormat('align',Formats.AlignHCenter)</tt><br>
* Set the foreground or background style as follows:<br>
* <tt>myLob.setParagraphFormat('fg style',Formats.SolidPattern)</tt><br>
* <tt>myLob.setParagraphFormat('bg style',Formats.CrossPattern)</tt><br>
* Set the foreground or background color as follows:<br>
* <tt>myLob.setParagraphFormat('fg color','\#ff007f')</tt><br>
* <tt>myLob.setParagraphFormat('bg color','\#000000')</tt><br>
* Note!! When setting a color, first ensure that the style has been set to
* something other than Formats.NoBrush, or your color settings will have no
* effect.</li>
* <li><tt>myLob.paragraphFormat(key)</tt> returns the current value for the given
* key. For a list of keys and what they mean, see immediately above.
* Note that some return values may be integers that need to be compared against values
* in the Formats data structure, described below. Furthermore,
* some may not be set at all, and thus return default values when queried.</li>
* <li>The above two functions can also be used without the "key" parameter. That is, you
* can lift a paragraph format out of one Lob using <tt>myLob.paragraphFormat()</tt> and
* then apply it to another Lob using <tt>myLob.setParagraphFormat(value)</tt>. (The
* value is a string that encodes all the formatting data; its format was not designed
* for reading/editing.)</li>
* <li><tt>myLob.setListFormat(key,value)</tt> sets an aspect of the list
* format of <tt>myLob</tt>, but only if it passes the <tt>isListItem()</tt>
* test. Note!! Changes made to one list item affect only that list item,
* not the entire list.
* Acceptable keys are those that appear in the following examples.<br>
* Indent the list as follows (zero for no indent, no negatives):<br>
* <tt>myLob.setListFormat('indent',3)</tt><br>
* Change the item's style as follows:<br>
* <tt>myLob.setListFormat('style',Formats.ListLowerAlpha)</tt><br>
* Change whether the item starts a new list (if false, it is part of an
* ongoing list):<br>
* <tt>myLob.setListFormat('new',true)</tt></li>
* <li><tt>myLob.setIsListItem(true)</tt> makes <tt>myLob</tt> a list item, if it
* is not already one. It will have the attribute \"new\" (discussed in
* <tt>setListFormat()</tt>) by default.<br>
* <tt>myLob.setIsListItem(false)</tt> makes <tt>myLob</tt> no longer a list
* item, or does nothing if it already was not one.<br>
* Both of these functions can only be applied to paragraph Lobs.</li>
* <li><tt>myLob.listFormat(key)</tt> returns the current value for the given
* key. For a list of keys and what they mean, see immediately above.
* Note that some return values may be integers that need to be compared against values
* in the Formats data structure. Furthermore,
* some may not be set at all, and thus return default values when queried.</li>
* <li>Two fo the above functions can also be used without the "key" parameter. That is,
* you can lift a list format out of one Lob using <tt>myLob.listFormat()</tt> and
* then apply it to another Lob using <tt>myLob.setListFormat(value)</tt>. (The
* value is a string that encodes all the formatting data; its format was not designed
* for reading/editing.)</li>
* <li><tt>myLob.normalize()</tt> finds any text blocks inside the Lob hierarchy
* <tt>myLob</tt> and combines any adjacent text fragments with identical
* character formatting.<br>
* In other words, it is possible for a block to contain a text fragment
* <tt>"hello "</tt> followed immediately by a text fragment
* <tt>"there!"</tt>, with neither having any formatting (or both having the
* same non-default formatting), when in reality such a block could be
* represented more simply with just one text fragment. Thus we provide this
* normalization routine that combines all such sequences into one.<br>
* Any other attributes of either text fragment are copied to the combined
* text fragment, with those of the first (left) text fragment taking
* precedence in the case of conflicts.</li>
* </ul>
*
* <h3>Global Formats object</h3>
* This routine also provides a global object called <tt>Formats</tt> that
* stores constants relating to text, paragraphs, and lists.
* These constants all come from the underlying Qt framework on which
* Lurch is built. You can search Qt docs for any of these constants
* for more information.
*
* \code
* // Brush patterns
* Formats.NoBrush == Qt::NoBrush
* Formats.SolidPattern == Qt::SolidPattern
* Formats.Dense1Pattern == Qt::Dense1Pattern
* Formats.Dense2Pattern == Qt::Dense2Pattern
* Formats.Dense3Pattern == Qt::Dense3Pattern
* Formats.Dense4Pattern == Qt::Dense4Pattern
* Formats.Dense5Pattern == Qt::Dense5Pattern
* Formats.Dense6Pattern == Qt::Dense6Pattern
* Formats.Dense7Pattern == Qt::Dense7Pattern
* Formats.HorPattern == Qt::HorPattern
* Formats.VerPattern == Qt::VerPattern
* Formats.CrossPattern == Qt::CrossPattern
* Formats.BDiagPattern == Qt::BDiagPattern
* Formats.FDiagPattern == Qt::FDiagPattern
* Formats.DiagCrossPattern == Qt::DiagCrossPattern
* Formats.LinearGradientPattern == Qt::LinearGradientPattern
* Formats.ConicalGradientPattern == Qt::ConicalGradientPattern
* Formats.RadialGradientPattern == Qt::RadialGradientPattern
* // Alignments
* Formats.AlignLeft == Qt::AlignLeft
* Formats.AlignRight == Qt::AlignRight
* Formats.AlignJustify == Qt::AlignJustify
* Formats.AlignHCenter == Qt::AlignHCenter
* Formats.AlignTop == Qt::AlignTop
* Formats.AlignBottom == Qt::AlignBottom
* Formats.AlignVCenter == Qt::AlignVCenter
* Formats.AlignCenter == Qt::AlignCenter
* // Font weights
* Formats.Light == QFont::Light
* Formats.Normal == QFont::Normal
* Formats.DemiBold == QFont::DemiBold
* Formats.Bold == QFont::Bold
* Formats.Black == QFont::Black
* // List styles
* Formats.ListDisc == QTextListFormat::ListDisc
* Formats.ListCircle == QTextListFormat::ListCircle
* Formats.ListSquare == QTextListFormat::ListSquare
* Formats.ListDecimal == QTextListFormat::ListDecimal
* Formats.ListLowerAlpha == QTextListFormat::ListLowerAlpha
* Formats.ListUpperAlpha == QTextListFormat::ListUpperAlpha
* Formats.ListLowerRoman == QTextListFormat::ListLowerRoman
* Formats.ListUpperRoman == QTextListFormat::ListUpperRoman
* \endcode
*/
void addLobTextToScriptEngine ( QScriptEngine& engine );
/** \brief A class that can hear a signal from a LurchEnvironment and refill its engine with the
* text API
*
* LurchEnvironments recreate their script engines regularly for various reasons, and thus need
* to have the new versions refilled with any necessary tools, such as the Lob text API provided
* by addLobTextToScriptEngine(). This class is simply a slot that calls that function, and
* thus it can be connected to LurchEnvironment::newScriptEngine().
*/
class KeepLobTextAdded : public QObject
{
Q_OBJECT
public slots:
/** \brief Calls addLobTextToScriptEngine() on \a engine
*
* Can be connected to LurchEnvironment::newScriptEngine() signal.
*/
void addLobText ( QScriptEngine* engine );
};
#endif // QTEXTDOCUMENTSCRIPT_H