2002-09-25 14:26:13 +00:00
/**
2007-04-25 01:24:38 +00:00
* \ file InsetFloat . cpp
2002-09-25 14:26:13 +00:00
* This file is part of LyX , the document processor .
* Licence details can be found in the file COPYING .
2002-03-21 17:09:55 +00:00
*
2008-11-14 15:58:50 +00:00
* \ author Jürgen Vigna
* \ author Lars Gullik Bjønnes
* \ author Jürgen Spitzmüller
2002-03-21 17:09:55 +00:00
*
2003-08-23 00:17:00 +00:00
* Full author contact details are available in file CREDITS .
2002-09-25 14:26:13 +00:00
*/
2000-06-28 13:35:52 +00:00
2003-05-13 09:48:57 +00:00
# include <config.h>
2000-06-28 13:35:52 +00:00
2020-06-08 21:27:49 +00:00
# include "InsetBox.h"
2008-03-02 11:30:50 +00:00
# include "InsetCaption.h"
2020-06-08 21:27:49 +00:00
# include "InsetFloat.h"
# include "InsetGraphics.h"
# include "InsetLabel.h"
2003-03-05 19:46:08 +00:00
2007-04-26 04:41:58 +00:00
# include "Buffer.h"
# include "BufferParams.h"
2003-03-05 19:46:08 +00:00
# include "BufferView.h"
2007-08-12 21:43:58 +00:00
# include "Counters.h"
2007-04-26 14:56:30 +00:00
# include "Cursor.h"
2007-04-26 04:41:58 +00:00
# include "DispatchResult.h"
2003-03-05 19:46:08 +00:00
# include "Floating.h"
# include "FloatList.h"
2007-04-26 04:41:58 +00:00
# include "FuncRequest.h"
2005-04-22 08:57:22 +00:00
# include "FuncStatus.h"
2003-03-05 19:46:08 +00:00
# include "LaTeXFeatures.h"
2007-04-26 11:30:54 +00:00
# include "Lexer.h"
2020-07-11 10:30:14 +00:00
# include "xml.h"
2020-07-09 15:19:01 +00:00
# include "output_docbook.h"
2009-11-30 17:20:37 +00:00
# include "output_xhtml.h"
2008-03-02 11:30:50 +00:00
# include "ParIterator.h"
2016-06-19 02:39:38 +00:00
# include "TexRow.h"
# include "texstream.h"
2007-11-07 23:25:08 +00:00
# include "TextClass.h"
2019-05-09 23:35:40 +00:00
# include "InsetList.h"
2003-03-05 19:46:08 +00:00
2008-02-18 07:14:42 +00:00
# include "support/debug.h"
2008-06-18 18:54:31 +00:00
# include "support/docstream.h"
2008-02-18 07:14:42 +00:00
# include "support/gettext.h"
2001-07-30 11:56:00 +00:00
# include "support/lstrings.h"
2008-03-27 22:26:24 +00:00
# include "frontends/Application.h"
2004-07-24 10:55:30 +00:00
2007-12-12 10:16:00 +00:00
using namespace std ;
2010-02-10 17:33:39 +00:00
using namespace lyx : : support ;
2006-10-21 00:16:43 +00:00
2008-03-27 22:26:24 +00:00
namespace lyx {
2003-05-13 16:24:49 +00:00
2000-06-28 13:35:52 +00:00
// With this inset it will be possible to support the latex package
// float.sty, and I am sure that with this and some additional support
// classes we can support similar functionality in other formats
// (read DocBook).
// By using float.sty we will have the same handling for all floats, both
Run codespell on src/insets
Command was
codespell -w -i 3 -S Makefile.in -L mathed,afe,tthe,ue,fro,uint,larg,alph,te,thes,alle,Claus,pres,pass-thru src/insets/
2020-06-25 21:46:16 +00:00
// for those already in existence (table and figure) and all user created
2008-11-14 15:58:50 +00:00
// ones¹. So suddenly we give the users the possibility of creating new
2000-06-28 13:35:52 +00:00
// kinds of floats on the fly. (and with a uniform look)
//
// API to float.sty:
// \newfloat{type}{placement}{ext}[within]
// type - The "type" of the new class of floats, like program or
// algorithm. After the appropriate \newfloat, commands
// such as \begin{program} or \end{algorithm*} will be
// available.
// placement - The default placement for the given class of floats.
// They are like in standard LaTeX: t, b, p and h for top,
// bottom, page, and here, respectively. On top of that
// there is a new type, H, which does not really correspond
// to a float, since it means: put it "here" and nowhere else.
// Note, however that the H specifier is special and, because
// of implementation details cannot be used in the second
// argument of \newfloat.
// ext - The file name extension of an auxiliary file for the list
// of figures (or whatever). LaTeX writes the captions to
// this file.
// within - This (optional) argument determines whether floats of this
// class will be numbered within some sectional unit of the
// document. For example, if within is equal to chapter, the
2002-03-21 17:09:55 +00:00
// floats will be numbered within chapters.
2000-06-28 13:35:52 +00:00
// \floatstyle{style}
// style - plain, boxed, ruled
// \floatname{float}{floatname}
// float -
// floatname -
// \floatplacement{float}{placement}
// float -
// placement -
// \restylefloat{float}
// float -
// \listof{type}{title}
// title -
2008-11-14 15:58:50 +00:00
// ¹ the algorithm float is defined using the float.sty package. Like this
2000-06-28 13:35:52 +00:00
// \floatstyle{ruled}
// \newfloat{algorithm}{htbp}{loa}[<sect>]
// \floatname{algorithm}{Algorithm}
//
2001-03-11 03:20:44 +00:00
// The intention is that floats should be definable from two places:
// - layout files
// - the "gui" (i.e. by the user)
//
// From layout files.
// This should only be done for floats defined in a documentclass and that
// does not need any additional packages. The two most known floats in this
// category is "table" and "figure". Floats defined in layout files are only
// stored in lyx files if the user modifies them.
//
// By the user.
// There should be a gui dialog (and also a collection of lyxfuncs) where
// the user can modify existing floats and/or create new ones.
//
// The individual floats will also have some settable
// variables: wide and placement.
//
2000-06-28 13:35:52 +00:00
// Lgb
2010-02-08 22:09:40 +00:00
//FIXME: why do we set in stone the type here?
2019-09-15 22:43:35 +00:00
InsetFloat : : InsetFloat ( Buffer * buf , string const & params_str )
2015-09-02 18:53:13 +00:00
: InsetCaptionable ( buf )
2000-06-28 13:35:52 +00:00
{
2010-02-10 17:33:39 +00:00
string2params ( params_str , params_ ) ;
2015-09-02 18:53:13 +00:00
setCaptionType ( params_ . type ) ;
}
// Enforce equality of float type and caption type.
void InsetFloat : : setCaptionType ( std : : string const & type )
{
2017-07-03 17:53:14 +00:00
InsetCaptionable : : setCaptionType ( type ) ;
2015-09-02 18:53:13 +00:00
params_ . type = captionType ( ) ;
// check if the float type exists
if ( buffer ( ) . params ( ) . documentClass ( ) . floats ( ) . typeExist ( params_ . type ) )
2017-04-11 22:22:23 +00:00
setNewLabel ( ) ;
2015-09-02 18:53:13 +00:00
else
setLabel ( bformat ( _ ( " ERROR: Unknown float type: %1$s " ) , from_utf8 ( params_ . type ) ) ) ;
2000-06-28 13:35:52 +00:00
}
2011-03-28 22:33:04 +00:00
docstring InsetFloat : : layoutName ( ) const
2017-07-03 17:53:14 +00:00
{
2010-02-10 17:33:39 +00:00
return " Float: " + from_utf8 ( params_ . type ) ;
2008-11-05 15:35:02 +00:00
}
2008-04-10 09:22:49 +00:00
docstring InsetFloat : : toolTip ( BufferView const & bv , int x , int y ) const
{
2010-11-17 17:25:22 +00:00
if ( isOpen ( bv ) )
2015-09-02 18:53:13 +00:00
return InsetCaptionable : : toolTip ( bv , x , y ) ;
2008-04-27 14:47:07 +00:00
2008-04-10 09:22:49 +00:00
OutputParams rp ( & buffer ( ) . params ( ) . encoding ( ) ) ;
2008-08-29 00:38:51 +00:00
return getCaptionText ( rp ) ;
2008-04-10 09:22:49 +00:00
}
2007-04-26 14:56:30 +00:00
void InsetFloat : : doDispatch ( Cursor & cur , FuncRequest & cmd )
2000-06-28 13:35:52 +00:00
{
2010-04-09 19:00:42 +00:00
switch ( cmd . action ( ) ) {
2003-08-05 08:07:07 +00:00
2003-03-05 19:46:08 +00:00
case LFUN_INSET_MODIFY : {
2020-07-13 14:46:43 +00:00
if ( ! buffer ( ) . params ( ) . documentClass ( ) . floats ( ) . typeExist ( cmd . getArg ( 0 ) ) ) {
// not for us: pass further.
cur . undispatched ( ) ;
break ;
}
2003-03-05 19:46:08 +00:00
InsetFloatParams params ;
2008-03-27 22:26:24 +00:00
string2params ( to_utf8 ( cmd . argument ( ) ) , params ) ;
2015-03-12 14:57:29 +00:00
cur . recordUndoInset ( this ) ;
2008-08-19 14:56:12 +00:00
// placement, wide and sideways are not used for subfloats
if ( ! params_ . subfloat ) {
params_ . placement = params . placement ;
params_ . wide = params . wide ;
params_ . sideways = params . sideways ;
}
2018-05-10 18:15:11 +00:00
params_ . alignment = params . alignment ;
2009-07-13 12:56:20 +00:00
setNewLabel ( ) ;
2015-09-02 18:53:13 +00:00
if ( params_ . type ! = params . type )
setCaptionType ( params . type ) ;
2010-07-09 14:37:00 +00:00
// what we really want here is a TOC update, but that means
// a full buffer update
cur . forceBufferUpdate ( ) ;
2004-02-16 11:58:51 +00:00
break ;
2000-07-17 18:27:53 +00:00
}
2003-03-07 15:58:02 +00:00
case LFUN_INSET_DIALOG_UPDATE : {
2008-03-27 22:26:24 +00:00
cur . bv ( ) . updateDialog ( " float " , params2string ( params ( ) ) ) ;
2004-02-16 11:58:51 +00:00
break ;
2003-03-07 15:58:02 +00:00
}
2003-03-05 19:46:08 +00:00
default :
2015-09-02 18:53:13 +00:00
InsetCaptionable : : doDispatch ( cur , cmd ) ;
2004-02-16 11:58:51 +00:00
break ;
2001-05-31 16:48:26 +00:00
}
2003-03-05 17:56:47 +00:00
}
2002-03-21 17:09:55 +00:00
2007-04-26 14:56:30 +00:00
bool InsetFloat : : getStatus ( Cursor & cur , FuncRequest const & cmd ,
2005-04-22 08:57:22 +00:00
FuncStatus & flag ) const
{
2010-04-09 19:00:42 +00:00
switch ( cmd . action ( ) ) {
2005-04-22 08:57:22 +00:00
case LFUN_INSET_MODIFY :
2020-07-13 14:46:43 +00:00
if ( ! buffer ( ) . params ( ) . documentClass ( ) . floats ( ) . typeExist ( cmd . getArg ( 0 ) ) )
return Inset : : getStatus ( cur , cmd , flag ) ;
// fall through
2005-04-22 08:57:22 +00:00
case LFUN_INSET_DIALOG_UPDATE :
2008-05-29 15:14:00 +00:00
flag . setEnabled ( true ) ;
2005-04-22 09:16:28 +00:00
return true ;
2005-04-22 08:57:22 +00:00
2009-08-06 22:42:42 +00:00
case LFUN_INSET_SETTINGS :
2015-09-02 18:53:13 +00:00
if ( InsetCaptionable : : getStatus ( cur , cmd , flag ) ) {
2009-08-06 22:42:42 +00:00
flag . setEnabled ( flag . enabled ( ) & & ! params_ . subfloat ) ;
return true ;
} else
return false ;
2017-07-03 17:53:14 +00:00
2014-01-26 19:22:39 +00:00
case LFUN_NEWLINE_INSERT :
if ( params_ . subfloat ) {
flag . setEnabled ( false ) ;
return true ;
}
2017-08-12 07:06:29 +00:00
// no subfloat:
// fall through
2009-08-06 22:42:42 +00:00
2005-04-22 08:57:22 +00:00
default :
2015-09-02 18:53:13 +00:00
return InsetCaptionable : : getStatus ( cur , cmd , flag ) ;
2005-04-22 08:57:22 +00:00
}
}
2015-09-02 18:53:13 +00:00
bool InsetFloat : : hasSubCaptions ( ParIterator const & it ) const
2015-09-01 16:08:35 +00:00
{
2015-09-02 18:53:13 +00:00
return ( it . innerInsetOfType ( FLOAT_CODE ) | | it . innerInsetOfType ( WRAP_CODE ) ) ;
2007-08-12 21:43:58 +00:00
}
2018-05-11 13:31:04 +00:00
string InsetFloat : : getAlignment ( ) const
{
string alignment ;
string const buf_alignment = buffer ( ) . params ( ) . float_alignment ;
if ( params_ . alignment = = " document "
& & ! buf_alignment . empty ( ) ) {
alignment = buf_alignment ;
} else if ( ! params_ . alignment . empty ( )
& & params_ . alignment ! = " class "
& & params_ . alignment ! = " document " ) {
alignment = params_ . alignment ;
}
return alignment ;
}
LyXAlignment InsetFloat : : contentAlignment ( ) const
{
LyXAlignment align = LYX_ALIGN_NONE ;
string alignment = getAlignment ( ) ;
if ( alignment = = " left " )
align = LYX_ALIGN_LEFT ;
else if ( alignment = = " center " )
align = LYX_ALIGN_CENTER ;
else if ( alignment = = " right " )
align = LYX_ALIGN_RIGHT ;
return align ;
}
2003-03-05 19:46:08 +00:00
void InsetFloatParams : : write ( ostream & os ) const
2003-03-05 17:56:47 +00:00
{
2015-09-02 18:53:13 +00:00
if ( type . empty ( ) ) {
// Better this than creating a parse error. This in fact happens in the
// parameters dialog via InsetFloatParams::params2string.
os < < " senseless " < < ' \n ' ;
} else
os < < type < < ' \n ' ;
2003-03-05 19:46:08 +00:00
2003-08-05 08:07:07 +00:00
if ( ! placement . empty ( ) )
2003-03-05 19:46:08 +00:00
os < < " placement " < < placement < < " \n " ;
2018-05-10 18:15:11 +00:00
if ( ! alignment . empty ( ) )
os < < " alignment " < < alignment < < " \n " ;
2003-08-05 08:07:07 +00:00
if ( wide )
2003-03-05 19:46:08 +00:00
os < < " wide true \n " ;
2003-08-05 08:07:07 +00:00
else
2003-03-05 19:46:08 +00:00
os < < " wide false \n " ;
2004-04-03 08:37:12 +00:00
2004-03-29 11:38:39 +00:00
if ( sideways )
os < < " sideways true \n " ;
else
os < < " sideways false \n " ;
2000-06-28 13:35:52 +00:00
}
2007-04-26 11:30:54 +00:00
void InsetFloatParams : : read ( Lexer & lex )
2000-06-28 13:35:52 +00:00
{
2008-04-05 10:34:29 +00:00
lex . setContext ( " InsetFloatParams::read " ) ;
2010-02-10 17:33:39 +00:00
lex > > type ;
2008-04-05 10:34:29 +00:00
if ( lex . checkFor ( " placement " ) )
2004-04-02 08:54:37 +00:00
lex > > placement ;
2018-05-10 18:15:11 +00:00
if ( lex . checkFor ( " alignment " ) )
lex > > alignment ;
2008-04-05 10:34:29 +00:00
lex > > " wide " > > wide ;
lex > > " sideways " > > sideways ;
2003-03-05 17:56:47 +00:00
}
2008-02-27 20:43:16 +00:00
void InsetFloat : : write ( ostream & os ) const
2003-03-05 19:46:08 +00:00
{
2010-02-08 22:09:40 +00:00
os < < " Float " ;
2003-03-05 19:46:08 +00:00
params_ . write ( os ) ;
2015-09-02 18:53:13 +00:00
InsetCaptionable : : write ( os ) ;
2003-03-05 19:46:08 +00:00
}
2008-02-27 20:43:16 +00:00
void InsetFloat : : read ( Lexer & lex )
2003-03-05 17:56:47 +00:00
{
2003-03-05 19:46:08 +00:00
params_ . read ( lex ) ;
2015-09-02 18:53:13 +00:00
InsetCaptionable : : read ( lex ) ;
setCaptionType ( params_ . type ) ;
2000-06-28 13:35:52 +00:00
}
2001-06-28 10:25:20 +00:00
void InsetFloat : : validate ( LaTeXFeatures & features ) const
2000-06-28 13:35:52 +00:00
{
2008-03-05 00:21:05 +00:00
if ( support : : contains ( params_ . placement , ' H ' ) )
2002-01-10 10:05:45 +00:00
features . require ( " float " ) ;
2004-04-03 08:37:12 +00:00
2004-03-29 11:38:39 +00:00
if ( params_ . sideways )
2008-01-11 18:56:53 +00:00
features . require ( " rotfloat " ) ;
2002-03-21 17:09:55 +00:00
2009-02-07 12:27:24 +00:00
if ( features . inFloat ( ) )
2008-03-02 11:30:50 +00:00
features . require ( " subfig " ) ;
2019-12-28 12:43:17 +00:00
if ( features . inDeletedInset ( ) ) {
features . require ( " tikz " ) ;
2019-12-27 08:50:11 +00:00
features . require ( " ct-tikz-object-sout " ) ;
2019-12-28 12:43:17 +00:00
}
2019-12-27 08:50:11 +00:00
2009-02-07 12:27:24 +00:00
features . useFloat ( params_ . type , features . inFloat ( ) ) ;
features . inFloat ( true ) ;
2015-09-02 18:53:13 +00:00
InsetCaptionable : : validate ( features ) ;
2009-02-07 12:27:24 +00:00
features . inFloat ( false ) ;
2000-06-28 13:35:52 +00:00
}
2019-05-09 23:35:40 +00:00
docstring InsetFloat : : xhtml ( XMLStream & xs , OutputParams const & rp ) const
2009-06-19 12:49:08 +00:00
{
FloatList const & floats = buffer ( ) . params ( ) . documentClass ( ) . floats ( ) ;
Floating const & ftype = floats . getType ( params_ . type ) ;
2009-11-30 17:08:56 +00:00
string const & htmltype = ftype . htmlTag ( ) ;
2010-01-07 17:32:04 +00:00
string const & attr = ftype . htmlAttrib ( ) ;
2009-06-19 12:49:08 +00:00
2009-11-30 17:20:37 +00:00
odocstringstream ods ;
2019-05-09 23:35:40 +00:00
XMLStream newxs ( ods ) ;
newxs < < xml : : StartTag ( htmltype , attr ) ;
2017-07-03 17:53:14 +00:00
InsetText : : XHTMLOptions const opts =
2009-11-30 17:20:37 +00:00
InsetText : : WriteLabel | InsetText : : WriteInnerTag ;
docstring deferred = InsetText : : insetAsXHTML ( newxs , rp , opts ) ;
2019-05-09 23:35:40 +00:00
newxs < < xml : : EndTag ( htmltype ) ;
2009-06-19 12:49:08 +00:00
2016-07-30 03:59:24 +00:00
if ( rp . inFloat = = OutputParams : : NONFLOAT ) {
2009-06-19 12:49:08 +00:00
// In this case, this float needs to be deferred, but we'll put it
// before anything the text itself deferred.
2009-11-30 17:20:37 +00:00
deferred = ods . str ( ) + ' \n ' + deferred ;
2016-07-30 03:59:24 +00:00
} else {
2009-06-19 12:49:08 +00:00
// In this case, the whole thing is already being deferred, so
// we can write to the stream.
2017-07-03 17:53:14 +00:00
// Note that things will already have been escaped, so we do not
2009-11-30 17:20:37 +00:00
// want to escape them again.
2019-05-09 23:35:40 +00:00
xs < < XMLStream : : ESCAPE_NONE < < ods . str ( ) ;
2016-07-30 03:59:24 +00:00
}
2009-11-30 17:20:37 +00:00
return deferred ;
2009-06-19 12:49:08 +00:00
}
2011-02-10 20:02:48 +00:00
void InsetFloat : : latex ( otexstream & os , OutputParams const & runparams_in ) const
2000-06-28 13:35:52 +00:00
{
2009-02-07 12:27:24 +00:00
if ( runparams_in . inFloat ! = OutputParams : : NONFLOAT ) {
2016-10-10 15:14:39 +00:00
if ( ! paragraphs ( ) . empty ( ) & & ! runparams_in . nice )
// improve TexRow precision in non-nice mode
os < < safebreakln ;
2009-02-07 12:27:24 +00:00
if ( runparams_in . moving_arg )
2008-03-02 11:30:50 +00:00
os < < " \\ protect " ;
os < < " \\ subfloat " ;
2014-12-04 16:27:56 +00:00
2009-02-07 12:27:24 +00:00
OutputParams rp = runparams_in ;
2014-12-04 16:27:56 +00:00
rp . moving_arg = true ;
2020-08-28 05:32:29 +00:00
rp . inFloat = OutputParams : : SUBFLOAT ;
2016-09-23 22:49:00 +00:00
os < < getCaption ( rp ) ;
2008-03-02 11:30:50 +00:00
os < < ' { ' ;
2015-02-20 10:51:40 +00:00
// The main argument is the contents of the float. This is not a moving argument.
rp . moving_arg = false ;
2011-02-10 20:02:48 +00:00
InsetText : : latex ( os , rp ) ;
2008-03-02 11:30:50 +00:00
os < < " } " ;
2014-12-04 16:27:56 +00:00
2011-02-10 20:02:48 +00:00
return ;
2008-03-02 11:30:50 +00:00
}
2009-02-07 12:27:24 +00:00
OutputParams runparams ( runparams_in ) ;
runparams . inFloat = OutputParams : : MAINFLOAT ;
2008-03-02 11:30:50 +00:00
2008-02-28 01:42:02 +00:00
FloatList const & floats = buffer ( ) . params ( ) . documentClass ( ) . floats ( ) ;
2008-01-11 18:56:53 +00:00
string tmptype = params_ . type ;
2015-05-22 16:59:17 +00:00
if ( params_ . sideways & & floats . allowsSideways ( params_ . type ) )
2008-01-11 18:56:53 +00:00
tmptype = " sideways " + params_ . type ;
2015-05-23 08:38:31 +00:00
if ( params_ . wide & & floats . allowsWide ( params_ . type )
2015-05-22 16:59:17 +00:00
& & ( ! params_ . sideways | |
params_ . type = = " figure " | |
params_ . type = = " table " ) )
2008-01-11 18:56:53 +00:00
tmptype + = " * " ;
2001-07-04 07:44:27 +00:00
// Figure out the float placement to use.
// From lowest to highest:
// - float default placement
// - document wide default placement
// - specific float placement
2015-05-22 08:37:14 +00:00
string tmpplacement ;
2008-02-27 20:43:16 +00:00
string const buf_placement = buffer ( ) . params ( ) . float_placement ;
2003-03-05 17:56:47 +00:00
string const def_placement = floats . defaultPlacement ( params_ . type ) ;
2018-05-10 18:15:11 +00:00
if ( params_ . placement = = " document "
& & ! buf_placement . empty ( )
& & buf_placement ! = def_placement ) {
2015-05-22 08:37:14 +00:00
tmpplacement = buf_placement ;
2018-05-10 18:15:11 +00:00
} else if ( ! params_ . placement . empty ( )
& & params_ . placement ! = " document "
& & params_ . placement ! = def_placement ) {
tmpplacement = params_ . placement ;
2015-05-22 08:37:14 +00:00
}
// Check if placement is allowed by this float
string const allowed_placement =
floats . allowedPlacement ( params_ . type ) ;
string placement ;
string : : const_iterator lit = tmpplacement . begin ( ) ;
string : : const_iterator end = tmpplacement . end ( ) ;
for ( ; lit ! = end ; + + lit ) {
if ( contains ( allowed_placement , * lit ) )
placement + = * lit ;
2001-07-04 07:44:27 +00:00
}
2002-03-21 17:09:55 +00:00
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
// Force \begin{<floatname>} to appear in a new line.
os < < breakln < < " \\ begin{ " < < from_ascii ( tmptype ) < < ' } ' ;
2011-03-12 01:40:01 +00:00
if ( runparams . lastid ! = - 1 )
os . texrow ( ) . start ( runparams . lastid , runparams . lastpos ) ;
2001-07-04 07:44:27 +00:00
// We only output placement if different from the def_placement.
2017-04-15 04:57:52 +00:00
// sidewaysfloats always use their own page,
// therefore don't output the p option that is always set
if ( ! placement . empty ( )
2019-09-15 22:43:35 +00:00
& & ( ! params_ . sideways | | from_ascii ( placement ) ! = " p " ) )
2006-10-21 00:16:43 +00:00
os < < ' [ ' < < from_ascii ( placement ) < < ' ] ' ;
2002-11-27 10:30:28 +00:00
os < < ' \n ' ;
2018-05-11 13:31:04 +00:00
2019-12-27 08:50:11 +00:00
if ( runparams . inDeletedInset ) {
2019-12-28 12:43:17 +00:00
// This has to be done manually since we need it inside the float
OutputParams : : CtObject ctobject = runparams . ctObject ;
runparams . ctObject = OutputParams : : CT_DISPLAYOBJECT ;
Changes : : latexMarkChange ( os , buffer ( ) . params ( ) , Change ( Change : : UNCHANGED ) ,
Change ( Change : : DELETED ) , runparams ) ;
runparams . ctObject = ctobject ;
2019-12-27 08:50:11 +00:00
}
2018-05-11 13:31:04 +00:00
string alignment = getAlignment ( ) ;
2018-05-10 18:15:11 +00:00
if ( alignment = = " left " )
os < < " \\ raggedright " < < breakln ;
else if ( alignment = = " center " )
os < < " \\ centering " < < breakln ;
else if ( alignment = = " right " )
os < < " \\ raggedleft " < < breakln ;
2002-03-21 17:09:55 +00:00
2011-02-10 20:02:48 +00:00
InsetText : : latex ( os , runparams ) ;
2002-05-05 15:15:51 +00:00
2019-12-27 08:50:11 +00:00
if ( runparams . inDeletedInset )
2019-12-28 12:43:17 +00:00
os < < " } " ;
2019-12-27 08:50:11 +00:00
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
// Force \end{<floatname>} to appear in a new line.
os < < breakln < < " \\ end{ " < < from_ascii ( tmptype ) < < " } \n " ;
2000-06-28 13:35:52 +00:00
}
2013-03-08 19:52:18 +00:00
int InsetFloat : : plaintext ( odocstringstream & os , OutputParams const & runparams , size_t max_length ) const
2007-02-16 08:15:16 +00:00
{
2008-02-27 20:43:16 +00:00
os < < ' [ ' < < buffer ( ) . B_ ( " float " ) < < ' '
2009-07-13 12:56:20 +00:00
< < floatName ( params_ . type ) < < " : \n " ;
2013-03-08 19:52:18 +00:00
InsetText : : plaintext ( os , runparams , max_length ) ;
2007-02-16 08:15:16 +00:00
os < < " \n ] " ;
2007-02-20 17:52:41 +00:00
return PLAINTEXT_NEWLINE + 1 ; // one char on a separate line
2007-02-16 08:15:16 +00:00
}
2020-06-08 21:27:49 +00:00
std : : vector < const InsetBox * > findSubfiguresInParagraph ( const Paragraph & par )
{
// Don't make the hypothesis that all subfigures are in the same paragraph.
// Similarly, there may be several subfigures in the same paragraph (most likely case, based on the documentation).
// Any box is considered as a subfigure, even though the most likely case is \minipage.
std : : vector < const InsetBox * > subfigures ;
for ( pos_type pos = 0 ; pos < par . size ( ) ; + + pos ) {
const Inset * inset = par . getInset ( pos ) ;
if ( ! inset )
continue ;
if ( const auto box = dynamic_cast < const InsetBox * > ( inset ) )
subfigures . push_back ( box ) ;
}
return subfigures ;
}
const InsetLabel * findLabelInParagraph ( const Paragraph & par )
2001-03-23 08:37:44 +00:00
{
2020-06-08 21:27:49 +00:00
for ( pos_type pos = 0 ; pos < par . size ( ) ; + + pos ) {
// If this inset is a subfigure, skip it.
const Inset * inset = par . getInset ( pos ) ;
if ( dynamic_cast < const InsetBox * > ( inset ) ) {
continue ;
}
2001-03-23 08:37:44 +00:00
2020-06-08 21:27:49 +00:00
// Maybe an inset is directly a label, in which case no more work is needed.
if ( inset & & dynamic_cast < const InsetLabel * > ( inset ) )
return dynamic_cast < const InsetLabel * > ( inset ) ;
// More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText).
if ( ! dynamic_cast < const InsetText * > ( inset ) )
continue ;
auto insetAsText = dynamic_cast < const InsetText * > ( inset ) ;
auto itIn = insetAsText - > paragraphs ( ) . begin ( ) ;
auto endIn = insetAsText - > paragraphs ( ) . end ( ) ;
for ( ; itIn ! = endIn ; + + itIn ) {
for ( pos_type posIn = 0 ; posIn < itIn - > size ( ) ; + + posIn ) {
const Inset * insetIn = itIn - > getInset ( posIn ) ;
if ( insetIn & & dynamic_cast < const InsetLabel * > ( insetIn ) ) {
return dynamic_cast < const InsetLabel * > ( insetIn ) ;
}
}
}
// Obviously, this solution does not scale with more levels of paragraphs-insets, but this should be enough.
}
return nullptr ;
}
const InsetCaption * findCaptionInParagraph ( const Paragraph & par )
{
// Don't dive too deep, otherwise, this could be a subfigure caption.
for ( pos_type pos = 0 ; pos < par . size ( ) ; + + pos ) {
// If this inset is a subfigure, skip it.
const Inset * inset = par . getInset ( pos ) ;
if ( dynamic_cast < const InsetBox * > ( inset ) )
continue ;
if ( inset & & dynamic_cast < const InsetCaption * > ( inset ) )
return dynamic_cast < const InsetCaption * > ( inset ) ;
}
return nullptr ;
}
2020-08-02 02:03:17 +00:00
void docbookSubfigures ( XMLStream & xs , OutputParams const & runparams , const InsetCaption * caption ,
const InsetLabel * label , std : : vector < const InsetBox * > & subfigures )
2020-06-08 21:27:49 +00:00
{
2020-08-02 02:03:17 +00:00
// Ensure there is no label output, it is supposed to be handled as xml:id.
OutputParams rpNoLabel = runparams ;
if ( label )
rpNoLabel . docbook_anchors_to_ignore . emplace ( label - > screenLabel ( ) ) ;
2020-06-08 21:27:49 +00:00
2020-08-02 02:03:17 +00:00
// First, open the formal group.
docstring attr = docstring ( ) ;
if ( label )
attr + = " xml:id= \" " + xml : : cleanID ( label - > screenLabel ( ) ) + " \" " ;
xs . startDivision ( false ) ;
xs < < xml : : StartTag ( " formalgroup " , attr ) ;
xs < < xml : : CR ( ) ;
xs < < xml : : StartTag ( " title " , attr ) ;
if ( caption ) {
caption - > getCaptionAsDocBook ( xs , rpNoLabel ) ;
} else {
xs < < " No caption " ;
// No caption has been detected, but this tag is required for the document to be valid DocBook.
}
xs < < xml : : EndTag ( " title " ) ;
xs < < xml : : CR ( ) ;
// Deal with each subfigure individually. This should also deal with their caption and their label.
// This should be a recursive call to InsetFloat.
for ( const InsetBox * subfigure : subfigures ) {
// If there is no InsetFloat in the paragraphs, output a warning.
bool foundInsetFloat = false ;
for ( const auto & it : subfigure - > paragraphs ( ) ) {
for ( pos_type posIn = 0 ; posIn < it . size ( ) ; + + posIn ) {
const Inset * inset = it . getInset ( posIn ) ;
if ( inset & & dynamic_cast < const InsetFloat * > ( inset ) ) {
foundInsetFloat = true ;
break ;
}
}
if ( foundInsetFloat )
break ;
2020-06-08 21:27:49 +00:00
}
2020-08-02 02:03:17 +00:00
if ( ! foundInsetFloat )
xs < < XMLStream : : ESCAPE_NONE < < " Error: no float found in the box. "
" To use subfigures in DocBook, elements must be wrapped in a float "
" inset and have a title/caption. " ;
// TODO: could also output a table, that would ensure that the document is correct and *displays* correctly (but without the right semantics), instead of just an error.
// Finally, recurse.
subfigure - > docbook ( xs , runparams ) ;
2020-06-08 21:27:49 +00:00
}
2020-08-02 02:03:17 +00:00
// Every subfigure is done: close the formal group.
xs < < xml : : EndTag ( " formalgroup " ) ;
xs < < xml : : CR ( ) ;
xs . endDivision ( ) ;
}
void docbookNoSubfigures ( XMLStream & xs , OutputParams const & runparams , const InsetCaption * caption ,
const InsetLabel * label , Floating const & ftype , const InsetFloat * thisFloat )
{
2020-06-08 21:27:49 +00:00
string const & titleTag = ftype . docbookCaption ( ) ;
// Ensure there is no label output, it is supposed to be handled as xml:id.
OutputParams rpNoLabel = runparams ;
if ( label )
rpNoLabel . docbook_anchors_to_ignore . emplace ( label - > screenLabel ( ) ) ;
// Ensure the float does not output its caption, as it is handled here (DocBook mandates a specific place for
// captions, they cannot appear at the end of the float, albeit LyX is happy with that).
OutputParams rpNoTitle = runparams ;
rpNoTitle . docbook_in_float = true ;
2020-08-02 02:03:17 +00:00
if ( ftype . floattype ( ) = = " table " )
rpNoTitle . docbook_in_table = true ;
2020-06-08 21:27:49 +00:00
2020-08-02 02:03:17 +00:00
// Organisation: <float> <title if any/> <contents without title/> </float>.
2020-06-08 21:27:49 +00:00
docstring attr = docstring ( ) ;
if ( label )
attr + = " xml:id= \" " + xml : : cleanID ( label - > screenLabel ( ) ) + " \" " ;
if ( ! ftype . docbookAttr ( ) . empty ( ) ) {
if ( ! attr . empty ( ) )
attr + = " " ;
attr + = from_utf8 ( ftype . docbookAttr ( ) ) ;
}
xs < < xml : : StartTag ( ftype . docbookTag ( caption ! = nullptr ) , attr ) ;
xs < < xml : : CR ( ) ;
2020-08-29 20:58:23 +00:00
if ( caption ) {
2020-06-08 21:27:49 +00:00
xs < < xml : : StartTag ( titleTag ) ;
caption - > getCaptionAsDocBook ( xs , rpNoLabel ) ;
xs < < xml : : EndTag ( titleTag ) ;
xs < < xml : : CR ( ) ;
}
2020-08-02 02:03:17 +00:00
thisFloat - > InsetText : : docbook ( xs , rpNoTitle ) ;
2020-06-08 21:27:49 +00:00
xs < < xml : : EndTag ( ftype . docbookTag ( caption ! = nullptr ) ) ;
xs < < xml : : CR ( ) ;
2001-03-23 08:37:44 +00:00
}
2020-08-02 02:03:17 +00:00
void InsetFloat : : docbook ( XMLStream & xs , OutputParams const & runparams ) const
{
// Determine whether the float has a title or not. For this, iterate through the paragraphs and look
// for an InsetCaption. Do the same for labels and subfigures.
// The caption and the label for each subfigure is handled by recursive calls.
const InsetCaption * caption = nullptr ;
const InsetLabel * label = nullptr ;
std : : vector < const InsetBox * > subfigures ;
auto end = paragraphs ( ) . end ( ) ;
for ( auto it = paragraphs ( ) . begin ( ) ; it ! = end ; + + it ) {
std : : vector < const InsetBox * > foundSubfigures = findSubfiguresInParagraph ( * it ) ;
if ( ! foundSubfigures . empty ( ) ) {
subfigures . reserve ( subfigures . size ( ) + foundSubfigures . size ( ) ) ;
subfigures . insert ( subfigures . end ( ) , foundSubfigures . begin ( ) , foundSubfigures . end ( ) ) ;
}
if ( ! caption )
caption = findCaptionInParagraph ( * it ) ;
if ( ! label )
label = findLabelInParagraph ( * it ) ;
}
// Gather a few things from global environment that are shared between all following cases.
FloatList const & floats = buffer ( ) . params ( ) . documentClass ( ) . floats ( ) ;
Floating const & ftype = floats . getType ( params_ . type ) ;
// Switch on subfigures.
if ( ! subfigures . empty ( ) )
docbookSubfigures ( xs , runparams , caption , label , subfigures ) ;
else
docbookNoSubfigures ( xs , runparams , caption , label , ftype , this ) ;
}
2007-10-13 09:04:52 +00:00
bool InsetFloat : : insetAllowed ( InsetCode code ) const
2001-07-12 14:35:38 +00:00
{
2017-07-03 17:53:14 +00:00
// The case that code == FLOAT_CODE is handled in Text3.cpp,
2009-07-21 20:04:52 +00:00
// because we need to know what type of float is meant.
switch ( code ) {
case WRAP_CODE :
case FOOT_CODE :
case MARGIN_CODE :
return false ;
default :
2015-09-02 18:53:13 +00:00
return InsetCaptionable : : insetAllowed ( code ) ;
2009-07-21 20:04:52 +00:00
}
2000-06-28 13:35:52 +00:00
}
2000-07-04 19:16:35 +00:00
2009-07-13 12:56:20 +00:00
void InsetFloat : : setWide ( bool w , bool update_label )
2000-07-15 23:51:46 +00:00
{
2015-05-22 16:59:17 +00:00
if ( ! buffer ( ) . params ( ) . documentClass ( ) . floats ( ) . allowsWide ( params_ . type ) )
params_ . wide = false ;
else
params_ . wide = w ;
2008-08-19 14:56:12 +00:00
if ( update_label )
2009-07-13 12:56:20 +00:00
setNewLabel ( ) ;
2000-07-15 23:51:46 +00:00
}
2009-07-13 12:56:20 +00:00
void InsetFloat : : setSideways ( bool s , bool update_label )
2004-03-29 11:38:39 +00:00
{
2015-05-22 16:59:17 +00:00
if ( ! buffer ( ) . params ( ) . documentClass ( ) . floats ( ) . allowsSideways ( params_ . type ) )
params_ . sideways = false ;
else
params_ . sideways = s ;
2008-08-19 14:56:12 +00:00
if ( update_label )
2009-07-13 12:56:20 +00:00
setNewLabel ( ) ;
2004-03-29 11:38:39 +00:00
}
2009-07-13 12:56:20 +00:00
void InsetFloat : : setSubfloat ( bool s , bool update_label )
2008-03-02 11:30:50 +00:00
{
params_ . subfloat = s ;
2008-08-19 14:56:12 +00:00
if ( update_label )
2009-07-13 12:56:20 +00:00
setNewLabel ( ) ;
2008-08-19 14:56:12 +00:00
}
2009-07-13 12:56:20 +00:00
void InsetFloat : : setNewLabel ( )
2008-08-19 14:56:12 +00:00
{
docstring lab = _ ( " float: " ) ;
2008-11-23 14:46:33 +00:00
if ( params_ . subfloat )
2008-08-19 14:56:12 +00:00
lab = _ ( " subfloat: " ) ;
2009-07-13 12:56:20 +00:00
lab + = floatName ( params_ . type ) ;
2008-08-19 14:56:12 +00:00
2015-05-22 16:59:17 +00:00
FloatList const & floats = buffer ( ) . params ( ) . documentClass ( ) . floats ( ) ;
if ( params_ . wide & & floats . allowsWide ( params_ . type ) )
2008-08-19 14:56:12 +00:00
lab + = ' * ' ;
2015-05-22 16:59:17 +00:00
if ( params_ . sideways & & floats . allowsSideways ( params_ . type ) )
2008-08-19 14:56:12 +00:00
lab + = _ ( " (sideways) " ) ;
2008-03-02 11:30:50 +00:00
setLabel ( lab ) ;
}
2013-03-22 21:23:38 +00:00
bool InsetFloat : : allowsCaptionVariation ( std : : string const & newtype ) const
{
2016-03-25 18:22:57 +00:00
return ! params_ . subfloat & & newtype ! = " Unnumbered " ;
2013-03-22 21:23:38 +00:00
}
2016-09-23 22:49:00 +00:00
TexString InsetFloat : : getCaption ( OutputParams const & runparams ) const
2015-10-13 22:51:50 +00:00
{
2009-06-19 12:18:38 +00:00
InsetCaption const * ins = getCaptionInset ( ) ;
if ( ins = = 0 )
2016-09-23 22:49:00 +00:00
return TexString ( ) ;
2015-10-13 22:51:50 +00:00
2016-09-23 22:49:00 +00:00
otexstringstream os ;
2015-10-13 22:51:50 +00:00
ins - > getArgs ( os , runparams ) ;
2009-06-19 12:18:38 +00:00
2016-10-10 15:14:39 +00:00
if ( ! runparams . nice )
// increase TexRow precision in non-nice mode
os < < safebreakln ;
2015-10-13 22:51:50 +00:00
os < < ' [ ' ;
2016-09-04 02:21:19 +00:00
otexstringstream os2 ;
ins - > getArgument ( os2 , runparams ) ;
TexString ts = os2 . release ( ) ;
docstring & arg = ts . str ;
2011-02-02 11:05:56 +00:00
// Protect ']'
if ( arg . find ( ' ] ' ) ! = docstring : : npos )
arg = ' { ' + arg + ' } ' ;
2016-09-04 02:21:19 +00:00
os < < move ( ts ) ;
2015-10-13 22:51:50 +00:00
os < < ' ] ' ;
2016-10-10 15:14:39 +00:00
if ( ! runparams . nice )
os < < safebreakln ;
2016-09-23 22:49:00 +00:00
return os . release ( ) ;
2008-03-02 11:30:50 +00:00
}
2008-03-27 22:26:24 +00:00
void InsetFloat : : string2params ( string const & in , InsetFloatParams & params )
2003-03-05 19:46:08 +00:00
{
params = InsetFloatParams ( ) ;
2003-04-24 20:02:49 +00:00
if ( in . empty ( ) )
return ;
2003-05-21 21:20:50 +00:00
2003-09-15 11:00:00 +00:00
istringstream data ( in ) ;
2008-04-02 23:06:22 +00:00
Lexer lex ;
2003-03-07 14:08:10 +00:00
lex . setStream ( data ) ;
2008-04-05 10:34:29 +00:00
lex . setContext ( " InsetFloat::string2params " ) ;
2003-12-11 15:23:15 +00:00
params . read ( lex ) ;
2003-03-05 19:46:08 +00:00
}
2008-03-27 22:26:24 +00:00
string InsetFloat : : params2string ( InsetFloatParams const & params )
2003-03-05 19:46:08 +00:00
{
ostringstream data ;
params . write ( data ) ;
2003-09-15 11:00:00 +00:00
return data . str ( ) ;
2003-03-05 19:46:08 +00:00
}
2006-10-21 00:16:43 +00:00
} // namespace lyx