From 4ce743a0a77d85d5e1722a3f2854ce163e40b353 Mon Sep 17 00:00:00 2001 From: Bo Peng Date: Wed, 9 May 2007 19:11:42 +0000 Subject: [PATCH] Add support for listings package. Two listings command \lstinline, \lstinputlisting and an environment \lstlisting are supported, along with preamble \lstset. \lstinputlisting is implemented through Include dialog, and the other two are implemented with a new inset listings, along with its dialog. * src/LyXAction.cpp: listing-insert action * src/insets/Inset.h,cpp: LISTINGS_CODE * src/insets/InsetInclude.cpp: handle \lstinputlisting * src/insets/InsetListings.h,cpp: new listings inset * src/insets/InsetListingsParams.h,cpp: parameters from listings package * src/insets/InsetCommandParams.h,cpp: handle lstinputlisting option * src/Bidi.cpp: handle LISTINGS_CODE * src/frontends/qt4/ui/TextLayoutUi.ui: update UI * src/frontends/qt4/ui/ListingsUi.ui: new dialog * src/frontends/qt4/ui/IncludeUi.ui: update UI * src/frontends/qt4/QInclude.h,cpp: add lstinputlisting * src/frontends/qt4/QDocument.h,cpp: add textedit for preamble listings_params * src/frontends/qt4/QListings.h,cpp: new listings inset * src/frontends/qt4/Dialogs.cpp: new listings dialog * src/frontends/controllers/ControlInclude.h,cpp: add lstinputlisting * src/frontends/controllers/ControlListings.h,cpp: new listings inset * src/LyXFunc.cpp: handle LISTING_CODE * src/Paragraph.cpp: handle LISTING_CODE * src/factory.cpp: new listings inset * src/CutAndPaste.cpp: handle LISTINGS_CODE * src/LaTeXFeatures.cpp: require listings * src/Text3.cpp: Handle LISTINGS_CODE * src/lfuns.h: add LFUN_LISTING_INSERT * src/Buffer.cpp: change lyx file format to 269 * src/BufferParams.h,cpp: add listings_params to preamble * lib/lyx2lyx/LyX.py: lyx2lyx * lib/lyx2lyx/lyx_1_5.py: lyx2lyx * lib/ui/stdmenus.inc: new menu item (no shortcut!) * src/insets/Makefile.am: update autotools * src/frontends/controllers/Makefile.am * src/frontends/qt4/Makefile.dialogs * src/frontends/qt4/Makefile.am * po/POTFILES.in: a few more translatable files. * development/scons/scons_manifest.py: scons build system * development/FORMAT: document format changes git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@18243 a592a061-630c-0410-9148-cb99ea01b6c8 --- development/FORMAT | 10 + development/scons/scons_manifest.py | 10 + lib/lyx2lyx/LyX.py | 2 +- lib/lyx2lyx/lyx_1_5.py | 141 ++++- lib/ui/stdmenus.inc | 1 + po/POTFILES.in | 4 + src/Bidi.cpp | 2 +- src/Buffer.cpp | 2 +- src/BufferParams.cpp | 30 + src/BufferParams.h | 2 + src/CutAndPaste.cpp | 5 +- src/LaTeXFeatures.cpp | 3 + src/LyXAction.cpp | 1 + src/LyXFunc.cpp | 13 +- src/Paragraph.cpp | 8 +- src/Text3.cpp | 6 + src/factory.cpp | 11 + src/frontends/controllers/ControlInclude.cpp | 2 + src/frontends/controllers/ControlInclude.h | 4 +- src/frontends/controllers/ControlListings.cpp | 56 ++ src/frontends/controllers/ControlListings.h | 50 ++ src/frontends/controllers/Makefile.am | 2 + src/frontends/qt4/Dialogs.cpp | 8 +- src/frontends/qt4/Makefile.am | 1 + src/frontends/qt4/Makefile.dialogs | 2 + src/frontends/qt4/QDocument.cpp | 33 ++ src/frontends/qt4/QDocument.h | 1 + src/frontends/qt4/QInclude.cpp | 70 ++- src/frontends/qt4/QInclude.h | 1 + src/frontends/qt4/QListings.cpp | 137 +++++ src/frontends/qt4/QListings.h | 61 ++ src/frontends/qt4/ui/IncludeUi.ui | 503 ++++++++++------- src/frontends/qt4/ui/ListingsUi.ui | 160 ++++++ src/frontends/qt4/ui/TextLayoutUi.ui | 473 ++++++++++------ src/insets/Inset.cpp | 1 + src/insets/Inset.h | 4 +- src/insets/InsetCommandParams.cpp | 7 + src/insets/InsetCommandParams.h | 8 +- src/insets/InsetInclude.cpp | 35 +- src/insets/InsetListings.cpp | 285 ++++++++++ src/insets/InsetListings.h | 99 ++++ src/insets/InsetListingsParams.cpp | 523 ++++++++++++++++++ src/insets/InsetListingsParams.h | 100 ++++ src/insets/Makefile.am | 4 + src/lfuns.h | 1 + 45 files changed, 2487 insertions(+), 395 deletions(-) create mode 100644 src/frontends/controllers/ControlListings.cpp create mode 100644 src/frontends/controllers/ControlListings.h create mode 100644 src/frontends/qt4/QListings.cpp create mode 100644 src/frontends/qt4/QListings.h create mode 100644 src/frontends/qt4/ui/ListingsUi.ui create mode 100644 src/insets/InsetListings.cpp create mode 100644 src/insets/InsetListings.h create mode 100644 src/insets/InsetListingsParams.cpp create mode 100644 src/insets/InsetListingsParams.h diff --git a/development/FORMAT b/development/FORMAT index 11d31ca931..6d1170b79d 100644 --- a/development/FORMAT +++ b/development/FORMAT @@ -1,6 +1,16 @@ LyX file-format changes ----------------------- +2007-05-08 Bo Peng + * format incremented to 269: add listings support + - add preamble flag \listings_params, e.g. \listings_params "language=Python,float" + - add inset listings, with options lstparams and inline, e.g. + \begin_inset listings + lstparams "xleftmargin=50pt,language=Python" + inline false + - add \lstinputlisting Include type. e.g. + \begin_inset Include \lstinputlisting{newfile1.lyx}[firstline=10,lastline=15] + 2007-05-06 Uwe Stöhr * format incremented to 268: add support for the CJK encodings diff --git a/development/scons/scons_manifest.py b/development/scons/scons_manifest.py index 1c69a5f4d6..2946c380c9 100644 --- a/development/scons/scons_manifest.py +++ b/development/scons/scons_manifest.py @@ -726,6 +726,7 @@ src_frontends_controllers_header_files = Split(''' ControlFloat.h ControlGraphics.h ControlInclude.h + ControlListings.h ControlLog.h ControlMath.h ControlNote.h @@ -771,6 +772,7 @@ src_frontends_controllers_files = Split(''' ControlFloat.cpp ControlGraphics.cpp ControlInclude.cpp + ControlListings.cpp ControlLog.cpp ControlMath.cpp ControlNote.cpp @@ -866,6 +868,7 @@ src_frontends_qt4_header_files = Split(''' QInclude.h QIndex.h QKeySymbol.h + QListings.h QLImage.h QLMenubar.h QLPainter.h @@ -955,6 +958,7 @@ src_frontends_qt4_files = Split(''' QInclude.cpp QIndex.cpp QKeySymbol.cpp + QListings.cpp QLImage.cpp QLMenubar.cpp QLPainter.cpp @@ -1030,6 +1034,7 @@ src_frontends_qt4_moc_files = Split(''' QGraphicsDialog.cpp QInclude.cpp QIndex.cpp + QListings.cpp QLMenubar.cpp QLPopupMenu.cpp QLPrintDialog.cpp @@ -1101,6 +1106,7 @@ src_frontends_qt4_ui_files = Split(''' IndexUi.ui LaTeXUi.ui LanguageUi.ui + ListingsUi.ui LogUi.ui MarginsUi.ui MathMatrixUi.ui @@ -1183,6 +1189,8 @@ src_insets_header_files = Split(''' InsetIndex.h InsetLabel.h InsetLine.h + InsetListings.h + InsetListingsParams.h InsetMarginal.h InsetNewline.h InsetNomencl.h @@ -1236,6 +1244,8 @@ src_insets_files = Split(''' InsetIndex.cpp InsetLabel.cpp InsetLine.cpp + InsetListings.cpp + InsetListingsParams.cpp InsetMarginal.cpp InsetNewline.cpp InsetNomencl.cpp diff --git a/lib/lyx2lyx/LyX.py b/lib/lyx2lyx/LyX.py index 6fb4311b22..57f86ef600 100644 --- a/lib/lyx2lyx/LyX.py +++ b/lib/lyx2lyx/LyX.py @@ -74,7 +74,7 @@ format_relation = [("0_06", [200], generate_minor_versions("0.6" , 4)), ("1_2", [220], generate_minor_versions("1.2" , 4)), ("1_3", [221], generate_minor_versions("1.3" , 7)), ("1_4", range(222,246), generate_minor_versions("1.4" , 4)), - ("1_5", range(246,269), generate_minor_versions("1.5" , 0))] + ("1_5", range(246,270), generate_minor_versions("1.5" , 0))] def formats_list(): diff --git a/lib/lyx2lyx/lyx_1_5.py b/lib/lyx2lyx/lyx_1_5.py index b62be7a1b8..b3c0976a1f 100644 --- a/lib/lyx2lyx/lyx_1_5.py +++ b/lib/lyx2lyx/lyx_1_5.py @@ -1347,6 +1347,140 @@ def revert_CJK(document): document.header[i] = "\\language english" +def revert_preamble_listings_params(document): + " Revert preamble option \listings_params " + i = find_token(document.header, "\\listings_params", 0) + if i != -1: + document.preamble.append('\\usepackage{listings}') + document.preamble.append('\\lstset{%s}' % document.header[i].split()[1].strip('"')) + document.header.pop(i); + + +def revert_listings_inset(document): + r''' Revert listings inset to \lstinline or \begin, \end lstlisting, translate +FROM + +\begin_inset +lstparams "language=Delphi" +inline true +status open + +\begin_layout Standard +var i = 10; +\end_layout + +\end_inset + +TO + +\begin_inset ERT +status open +\begin_layout Standard + + +\backslash +lstinline[language=Delphi]{var i = 10;} +\end_layout + +\end_inset +''' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset listings', i) + if i == -1: + break + j = find_end_of_inset(document.body, i + 1) + if j == -1: + # this should not happen + break + inline = 'false' + params = '' + status = 'open' + inlinecode = '' + # first three lines + for line in range(i + 1, i + 4): + if document.body[line].startswith('inline'): + inline = document.body[line].split()[1] + if document.body[line].startswith('lstparams'): + params = document.body[line].split()[1].strip('"') + if document.body[line].startswith('status'): + status = document.body[line].split()[1].strip() + k = line + 1 + # looking for the oneline code for lstinline + for line in range(i + 2, j + 1): + if document.body[line].startswith(r'\begin_layout'): + inlinecode = document.body[line+1] + break + if inline == 'true': + document.body[i:(j+1)] = [r'\begin_inset ERT' + 'status %s' % status, + r'\begin_layout Standard', + '', + '', + r'\backslash', + 'lstinline[%s]{%s}' % (params, inlinecode), + r'\end_layout', + '', + r'\end_inset'] + else: + document.body[i: k] = [r'\begin_inset ERT', + 'status %s' % status, + '', + r'\begin_layout Standard', + '', + '', + r'\backslash', + r'lstlisting[%s]{' % params, + r'\end_layout' + ] + + +def revert_include_listings(document): + r''' Revert lstinputlisting Include option , translate +\begin_inset Include \lstinputlisting{file}[opt] +preview false + +\end_inset + +TO + +\begin_inset ERT +status open + +\begin_layout Standard + + +\backslash +lstinputlisting{file}[opt] +\end_layout + +\end_inset + ''' + + i = 0 + while True: + i = find_token(document.body, r'\begin_inset Include \lstinputlisting', i) + if i == -1: + break + j = find_end_of_inset(document.body, i + 1) + if j == -1: + # this should not happen + break + # find command line + cmd = document.body[i].split()[2] + document.body[i : j + 1] = [r'\begin_inset ERT', + 'status open', + '', + r'\begin_layout Standard', + '', + '', + r'\backslash', + '%s' % cmd[1:], + r'\end_layout', + '', + r'\end_inset'] + + ## # Conversion hub # @@ -1374,9 +1508,12 @@ convert = [[246, []], [265, [convert_tableborder]], [266, []], [267, []], - [268, []]] + [268, []], + [269, []]] -revert = [[267, [revert_CJK]], +revert = [ + [268, [revert_preamble_listings_params, revert_listings_inset, revert_include_listings]], + [267, [revert_CJK]], [266, [revert_utf8plain]], [265, [revert_armenian]], [264, [revert_tableborder]], diff --git a/lib/ui/stdmenus.inc b/lib/ui/stdmenus.inc index 698c8c18bc..8bfbf3a11c 100644 --- a/lib/ui/stdmenus.inc +++ b/lib/ui/stdmenus.inc @@ -311,6 +311,7 @@ Menuset Item "Marginal Note|M" "marginalnote-insert" Item "Short Title|S" "optional-insert" Item "TeX Code|X" "ert-insert" + Item "Program Listing" "listing-insert" Item "Date" "date-insert" End diff --git a/po/POTFILES.in b/po/POTFILES.in index 7f2a14f9b0..d3d88d2bea 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -67,6 +67,7 @@ src/frontends/qt4/QExternal.cpp src/frontends/qt4/QFloat.cpp src/frontends/qt4/QGraphics.cpp src/frontends/qt4/QInclude.cpp +src/frontends/qt4/QListings.cpp src/frontends/qt4/QMathMatrixDialog.cpp src/frontends/qt4/QNote.cpp src/frontends/qt4/QParagraph.cpp @@ -106,6 +107,7 @@ src/insets/InsetGraphics.cpp src/insets/InsetHFill.cpp src/insets/InsetInclude.cpp src/insets/InsetIndex.cpp +src/insets/InsetListings.cpp src/insets/InsetMarginal.cpp src/insets/InsetNomencl.cpp src/insets/InsetNote.cpp @@ -115,6 +117,7 @@ src/insets/InsetRef.cpp src/insets/InsetTOC.cpp src/insets/InsetTabular.cpp src/insets/InsetText.cpp +src/insets/InsetTheorem.cpp src/insets/InsetUrl.cpp src/insets/InsetVSpace.cpp src/insets/InsetWrap.cpp @@ -122,6 +125,7 @@ src/insets/RenderGraphic.cpp src/insets/RenderPreview.cpp src/lengthcommon.cpp src/lyxfind.cpp +src/mathed/InsetFormulaMacro.cpp src/mathed/InsetMathAMSArray.cpp src/mathed/InsetMathCases.cpp src/mathed/InsetMathGrid.cpp diff --git a/src/Bidi.cpp b/src/Bidi.cpp index 342e7e86f7..f90e007be1 100644 --- a/src/Bidi.cpp +++ b/src/Bidi.cpp @@ -59,7 +59,7 @@ void Bidi::computeTables(Paragraph const & par, return; } - if (par.ownerCode() == Inset::ERT_CODE) { + if (par.ownerCode() == Inset::ERT_CODE || par.ownerCode() == Inset::LISTINGS_CODE) { start_ = -1; return; } diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 33b6d2cb5b..1a2766eb21 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -141,7 +141,7 @@ using std::string; namespace { -int const LYX_FORMAT = 268; +int const LYX_FORMAT = 269; } // namespace anon diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 332b03da05..4d8b0b6ea6 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -37,6 +37,7 @@ #include "VSpace.h" #include "frontends/alert.h" +#include "insets/InsetListingsParams.h" #include "support/lyxalgo.h" // for lyx::count #include "support/convert.h" @@ -351,6 +352,7 @@ BufferParams::BufferParams() graphicsDriver = "default"; sides = TextClass::OneSide; columns = 1; + listings_params = string(); pagestyle = "default"; compressed = false; for (int iter = 0; iter < 4; ++iter) { @@ -603,6 +605,17 @@ string const BufferParams::readToken(Lexer & lex, string const & token) lex >> fontsize; } else if (token == "\\papercolumns") { lex >> columns; + } else if (token == "\\listings_params") { + string par; + lex >> par; + // validate par and produce a valid listings parameter string + try { + listings_params = InsetListingsParams(par).params(); + } catch (invalidParam & e) { + lyxerr << "Invalid parameter string " << par << endl; + lyxerr << e.what() << endl; + listings_params = string(); + } } else if (token == "\\papersides") { int psides; lex >> psides; @@ -734,6 +747,9 @@ void BufferParams::writeFile(ostream & os) const << "\n\\papercolumns " << columns << "\n\\papersides " << sides << "\n\\paperpagestyle " << pagestyle << '\n'; + if (!listings_params.empty()) + os << "\\listings_params \"" << + InsetListingsParams(listings_params).encodedString() << "\"\n"; for (int i = 0; i < 4; ++i) { if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) { if (user_defined_bullet(i).getFont() != -1) { @@ -946,6 +962,20 @@ bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features, texrow.newline(); } + if (!listings_params.empty()) { + os << "\\usepackage{listings}\n"; + texrow.newline(); + os << "\\lstset{"; + // do not test validity because listings_params is supposed to be valid + string par = InsetListingsParams(listings_params).separatedParams(true); + os << from_ascii(par); + // count the number of newlines + for (size_t i = 0; i < par.size(); ++i) + if (par[i] == '\n') + texrow.newline(); + os << "}\n"; + texrow.newline(); + } if (use_geometry || nonstandard_papersize) { os << "\\usepackage{geometry}\n"; texrow.newline(); diff --git a/src/BufferParams.h b/src/BufferParams.h index 64af381d16..45c8fbb4e2 100644 --- a/src/BufferParams.h +++ b/src/BufferParams.h @@ -189,6 +189,8 @@ public: std::string float_placement; /// unsigned int columns; + /// parameters for the listings package + std::string listings_params; /// TextClass::PageSides sides; /// diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index 6220982e02..c05e80130d 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -128,7 +128,8 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, // Convert newline to paragraph break in ERT inset. // This should not be here! if (pars[pit].inInset() && - pars[pit].inInset()->lyxCode() == Inset::ERT_CODE) { + (pars[pit].inInset()->lyxCode() == Inset::ERT_CODE || + pars[pit].inInset()->lyxCode() == Inset::LISTINGS_CODE)) { for (ParagraphList::size_type i = 0; i < insertion.size(); ++i) { for (pos_type j = 0; j < insertion[i].size(); ++j) { if (insertion[i].isNewline(j)) { @@ -374,7 +375,7 @@ void copySelectionHelper(Buffer const & buf, ParagraphList & pars, // ERT paragraphs have the Language latex_language. // This is invalid outside of ERT, so we need to change it // to the buffer language. - if (it->ownerCode() == Inset::ERT_CODE) { + if (it->ownerCode() == Inset::ERT_CODE || it->ownerCode() == Inset::LISTINGS_CODE) { it->changeLanguage(buf.params(), latex_language, buf.getLanguage()); } diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index 69546187dc..c5f73a9cdf 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -568,6 +568,9 @@ string const LaTeXFeatures::getPackages() const "\\providecommand{\\makenomenclature}{\\makeglossary}\n" "\\makenomenclature\n"; } + + if (mustProvide("listings")) + packages << "\\usepackage{listings}\n"; return packages.str(); } diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 61ab9e8e83..4f42742c90 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -371,6 +371,7 @@ void LyXAction::init() { LFUN_NOMENCL_PRINT, "nomencl-print", Noop }, { LFUN_CLEARPAGE_INSERT, "clearpage-insert", Noop }, { LFUN_CLEARDOUBLEPAGE_INSERT, "cleardoublepage-insert", Noop }, + { LFUN_LISTING_INSERT, "listing-insert", Noop }, { LFUN_NOACTION, "", Noop } }; diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index cabf8afa1f..fc1eb74a04 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -67,6 +67,7 @@ #include "insets/InsetERT.h" #include "insets/InsetExternal.h" #include "insets/InsetFloat.h" +#include "insets/InsetListings.h" #include "insets/InsetGraphics.h" #include "insets/InsetInclude.h" #include "insets/InsetNote.h" @@ -519,6 +520,9 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const case Inset::BOX_CODE: enable = cmd.argument() == "box"; break; + case Inset::LISTINGS_CODE: + enable = cmd.argument() == "listings"; + break; default: break; } @@ -558,7 +562,8 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const enable = Exporter::isExportable(*buf, "dvi") && lyxrc.print_command != "none"; else if (name == "character") - enable = cur.inset().lyxCode() != Inset::ERT_CODE; + enable = cur.inset().lyxCode() != Inset::ERT_CODE && + cur.inset().lyxCode() != Inset::LISTINGS_CODE; else if (name == "latexlog") enable = isFileReadable(FileName(buf->getLogName().second)); else if (name == "spellchecker") @@ -573,7 +578,8 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const } case LFUN_DIALOG_SHOW_NEW_INSET: - enable = cur.inset().lyxCode() != Inset::ERT_CODE; + enable = cur.inset().lyxCode() != Inset::ERT_CODE && + cur.inset().lyxCode() != Inset::LISTINGS_CODE; if (cur.inset().lyxCode() == Inset::CAPTION_CODE) { FuncStatus flag; if (cur.inset().getStatus(cur, cmd, flag)) @@ -1317,6 +1323,9 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } else if (name == "float") { InsetFloatParams p; data = InsetFloatMailer::params2string(p); + } else if (name == "listings") { + InsetListingsParams p; + data = InsetListingsMailer::params2string(p); } else if (name == "graphics") { InsetGraphicsParams p; Buffer const & buffer = *lyx_view_->buffer(); diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index ebe0e840c9..e0ae322881 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -2176,6 +2176,7 @@ bool Paragraph::emptyTag() const lyx_code != Inset::INCLUDE_CODE && lyx_code != Inset::GRAPHICS_CODE && lyx_code != Inset::ERT_CODE && + lyx_code != Inset::LISTINGS_CODE && lyx_code != Inset::FLOAT_CODE && lyx_code != Inset::TABULAR_CODE) { return false; @@ -2341,7 +2342,8 @@ bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const { return lyxrc.rtl_support && getParLanguage(bparams)->rightToLeft() - && ownerCode() != Inset::ERT_CODE; + && ownerCode() != Inset::ERT_CODE + && ownerCode() != Inset::LISTINGS_CODE; } @@ -2502,7 +2504,7 @@ bool Paragraph::isFreeSpacing() const // for now we just need this, later should we need this in some // other way we can always add a function to Inset too. - return ownerCode() == Inset::ERT_CODE; + return ownerCode() == Inset::ERT_CODE || ownerCode() == Inset::LISTINGS_CODE; } @@ -2510,7 +2512,7 @@ bool Paragraph::allowEmpty() const { if (layout()->keepempty) return true; - return ownerCode() == Inset::ERT_CODE; + return ownerCode() == Inset::ERT_CODE || ownerCode() == Inset::LISTINGS_CODE; } diff --git a/src/Text3.cpp b/src/Text3.cpp index 12a7d98ebb..c44fc3b312 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -1198,6 +1198,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_BRANCH_INSERT: case LFUN_BIBITEM_INSERT: case LFUN_ERT_INSERT: + case LFUN_LISTING_INSERT: case LFUN_FOOTNOTE_INSERT: case LFUN_MARGINALNOTE_INSERT: case LFUN_OPTIONAL_INSERT: @@ -1695,11 +1696,16 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, code = Inset::VSPACE_CODE; else if (cmd.argument() == "wrap") code = Inset::WRAP_CODE; + else if (cmd.argument() == "listings") + code = Inset::LISTINGS_CODE; break; case LFUN_ERT_INSERT: code = Inset::ERT_CODE; break; + case LFUN_LISTING_INSERT: + code = Inset::LISTINGS_CODE; + break; case LFUN_FOOTNOTE_INSERT: code = Inset::FOOT_CODE; break; diff --git a/src/factory.cpp b/src/factory.cpp index 54ae0c8965..09296591da 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -30,6 +30,7 @@ #include "insets/InsetCharStyle.h" #include "insets/InsetEnvironment.h" #include "insets/InsetERT.h" +#include "insets/InsetListings.h" #include "insets/InsetExternal.h" #include "insets/InsetFloat.h" #include "insets/InsetFloatList.h" @@ -136,6 +137,9 @@ Inset * createInset(BufferView * bv, FuncRequest const & cmd) case LFUN_ERT_INSERT: return new InsetERT(params); + case LFUN_LISTING_INSERT: + return new InsetListings(params); + case LFUN_FOOTNOTE_INSERT: return new InsetFoot(params); @@ -260,6 +264,11 @@ Inset * createInset(BufferView * bv, FuncRequest const & cmd) InsetCollapsable::CollapseStatus st; InsetERTMailer::string2params(to_utf8(cmd.argument()), st); return new InsetERT(params, st); + + } else if (name == "listings") { + InsetListingsParams par; + InsetListingsMailer::string2params(to_utf8(cmd.argument()), par); + return new InsetListings(params, par); } else if (name == "external") { Buffer const & buffer = *bv->buffer(); @@ -486,6 +495,8 @@ Inset * readInset(Lexer & lex, Buffer const & buf) inset.reset(new InsetEnvironment(buf.params(), lex.getString())); } else if (tmptok == "ERT") { inset.reset(new InsetERT(buf.params())); + } else if (tmptok == "listings") { + inset.reset(new InsetListings(buf.params())); } else if (tmptok == "InsetSpace") { inset.reset(new InsetSpace); } else if (tmptok == "Tabular") { diff --git a/src/frontends/controllers/ControlInclude.cpp b/src/frontends/controllers/ControlInclude.cpp index 762def9c13..c5a6b94e40 100644 --- a/src/frontends/controllers/ControlInclude.cpp +++ b/src/frontends/controllers/ControlInclude.cpp @@ -86,6 +86,8 @@ docstring const ControlInclude::browse(docstring const & in_name, Type in_type) break; case VERBATIM: break; + case LISTINGS: + break; } pair dir1(_("Documents|#o#O"), diff --git a/src/frontends/controllers/ControlInclude.h b/src/frontends/controllers/ControlInclude.h index 983a30cefd..441eff069e 100644 --- a/src/frontends/controllers/ControlInclude.h +++ b/src/frontends/controllers/ControlInclude.h @@ -34,7 +34,9 @@ public: /// VERBATIM, /// - INCLUDE + INCLUDE, + /// + LISTINGS, }; /// ControlInclude(Dialog &); diff --git a/src/frontends/controllers/ControlListings.cpp b/src/frontends/controllers/ControlListings.cpp new file mode 100644 index 0000000000..dc4e56dd39 --- /dev/null +++ b/src/frontends/controllers/ControlListings.cpp @@ -0,0 +1,56 @@ +/** + * \file ControlListings.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "ControlListings.h" +#include "FuncRequest.h" +#include "insets/InsetListings.h" + +#include "debug.h" + +using std::string; + +namespace lyx { +namespace frontend { + +ControlListings::ControlListings(Dialog & parent) + : Dialog::Controller(parent), params_() +{} + + +bool ControlListings::initialiseParams(string const & data) +{ + InsetListingsMailer::string2params(data, params_); + return true; +} + + +void ControlListings::clearParams() +{ + params_.clear(); +} + + +void ControlListings::dispatchParams() +{ + string const lfun = InsetListingsMailer::params2string(params()); + kernel().dispatch(FuncRequest(getLfun(), lfun)); +} + + +void ControlListings::setParams(InsetListingsParams const & params) +{ + params_ = params; +} + + +} // namespace frontend +} // namespace lyx diff --git a/src/frontends/controllers/ControlListings.h b/src/frontends/controllers/ControlListings.h new file mode 100644 index 0000000000..8e679eed94 --- /dev/null +++ b/src/frontends/controllers/ControlListings.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +/** + * \file ControlListings.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef CONTROLLISTINGS_H +#define CONTROLLISTINGS_H + +#include "Dialog.h" +#include "insets/InsetListingsParams.h" + +namespace lyx { + +class InsetListingsParams; + +namespace frontend { + +class ControlListings : public Dialog::Controller { +public: + /// + ControlListings(Dialog &); + /// + virtual bool initialiseParams(std::string const & data); + /// clean-up on hide. + virtual void clearParams(); + /// clean-up on hide. + virtual void dispatchParams(); + /// + virtual bool isBufferDependent() const { return true; } + /// + InsetListingsParams & params() { return params_; } + /// + InsetListingsParams const & params() const { return params_; } + /// + void setParams(InsetListingsParams const &); +private: + /// + InsetListingsParams params_; +}; + +} // namespace frontend +} // namespace lyx + +#endif diff --git a/src/frontends/controllers/Makefile.am b/src/frontends/controllers/Makefile.am index 563e2b298e..1dbae4707d 100644 --- a/src/frontends/controllers/Makefile.am +++ b/src/frontends/controllers/Makefile.am @@ -52,6 +52,8 @@ libcontrollers_la_SOURCES= \ ControlGraphics.cpp \ ControlGraphics.h \ ControlInclude.cpp \ + ControlListings.h \ + ControlListings.cpp \ ControlInclude.h \ ControlLog.cpp \ ControlLog.h \ diff --git a/src/frontends/qt4/Dialogs.cpp b/src/frontends/qt4/Dialogs.cpp index ba6c04d3d3..ec78bde553 100644 --- a/src/frontends/qt4/Dialogs.cpp +++ b/src/frontends/qt4/Dialogs.cpp @@ -25,6 +25,7 @@ #include "ControlFloat.h" #include "ControlGraphics.h" #include "ControlInclude.h" +#include "ControlListings.h" #include "ControlLog.h" #include "ControlViewSource.h" #include "ControlMath.h" @@ -66,6 +67,7 @@ #include "QIndex.h" #include "QMathMatrixDialog.h" #include "QNomencl.h" +#include "QListings.h" #include "QLog.h" #include "QViewSource.h" #include "QNote.h" @@ -112,7 +114,7 @@ char const * const dialognames[] = { "thesaurus", #endif -"texinfo", "toc", "url", "view-source", "vspace", "wrap" }; +"texinfo", "toc", "url", "view-source", "vspace", "wrap", "listings" }; char const * const * const end_dialognames = dialognames + (sizeof(dialognames) / sizeof(char *)); @@ -318,6 +320,10 @@ Dialogs::DialogPtr Dialogs::build(string const & name) dialog->setController(new ControlWrap(*dialog)); dialog->setView(new QWrap(*dialog)); dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); + } else if (name == "listings") { + dialog->setController(new ControlListings(*dialog)); + dialog->setView(new QListings(*dialog)); + dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy); } return dialog; diff --git a/src/frontends/qt4/Makefile.am b/src/frontends/qt4/Makefile.am index 8af7fafb56..c8a220b120 100644 --- a/src/frontends/qt4/Makefile.am +++ b/src/frontends/qt4/Makefile.am @@ -47,6 +47,7 @@ libqt4_la_SOURCES = \ QDialogView.cpp QDialogView.h \ QFloat.cpp QFloat.h \ QGraphics.cpp QGraphics.h \ + QListings.cpp QListings.h \ QLImage.cpp QLImage.h \ QViewSource.cpp QViewSource.h \ QLPainter.cpp QLPainter.h \ diff --git a/src/frontends/qt4/Makefile.dialogs b/src/frontends/qt4/Makefile.dialogs index 59722f3a8c..bea56106eb 100644 --- a/src/frontends/qt4/Makefile.dialogs +++ b/src/frontends/qt4/Makefile.dialogs @@ -27,6 +27,7 @@ UIFILES = \ IndexUi.ui \ LanguageUi.ui \ LaTeXUi.ui \ + ListingsUi.ui \ LogUi.ui \ MarginsUi.ui \ MathMatrixUi.ui \ @@ -108,6 +109,7 @@ MOCFILES = \ QIndex.cpp QIndex.h \ QLog.cpp QLog.h \ QViewSource.cpp QViewSource.h \ + QListings.cpp QListings.h \ QLMenubar.cpp QLMenubar.h \ QLPopupMenu.cpp QLPopupMenu.h \ QLPrintDialog.cpp QLPrintDialog.h \ diff --git a/src/frontends/qt4/QDocument.cpp b/src/frontends/qt4/QDocument.cpp index 9619957ed9..5174eaa66c 100644 --- a/src/frontends/qt4/QDocument.cpp +++ b/src/frontends/qt4/QDocument.cpp @@ -36,6 +36,7 @@ #include "TextClassList.h" #include "Spacing.h" +#include "insets/InsetListingsParams.h" #include "controllers/ControlDocument.h" #include "support/lstrings.h" @@ -143,6 +144,11 @@ QDocumentDialog::QDocumentDialog(QDocument * form) this, SLOT(enableSkip(bool))); connect(textLayoutModule->twoColumnCB, SIGNAL(clicked()), this, SLOT(change_adaptor())); + connect(textLayoutModule->listingsED, SIGNAL(textChanged()), + this, SLOT(change_adaptor())); + connect(textLayoutModule->listingsED, SIGNAL(textChanged()), + this, SLOT(validate_listings_params())); + textLayoutModule->listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters."); textLayoutModule->lspacingLE->setValidator(new QDoubleValidator( textLayoutModule->lspacingLE)); textLayoutModule->skipLE->setValidator(unsignedLengthValidator( @@ -540,6 +546,26 @@ void QDocumentDialog::change_adaptor() } +void QDocumentDialog::validate_listings_params() +{ + static bool isOK = true; + try { + InsetListingsParams par(fromqstr(textLayoutModule->listingsED->toPlainText())); + if (!isOK) { + isOK = true; + // listingsTB->setTextColor("black"); + textLayoutModule->listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters."); + okPB->setEnabled(true); + } + } catch (invalidParam & e) { + isOK = false; + // listingsTB->setTextColor("red"); + textLayoutModule->listingsTB->setPlainText(e.what()); + okPB->setEnabled(false); + } +} + + void QDocumentDialog::closeEvent(QCloseEvent * e) { form_->slotWMHide(); @@ -864,6 +890,9 @@ void QDocumentDialog::apply(BufferParams & params) else params.columns = 1; + // text should have passed validation + params.listings_params = InsetListingsParams(fromqstr(textLayoutModule->listingsED->toPlainText())).params(); + if (textLayoutModule->indentRB->isChecked()) params.paragraph_separation = BufferParams::PARSEP_INDENT; else @@ -1168,6 +1197,10 @@ void QDocumentDialog::updateParams(BufferParams const & params) textLayoutModule->twoColumnCB->setChecked( params.columns == 2); + + // break listings_params to multiple lines + string lstparams = InsetListingsParams(params.listings_params).separatedParams(); + textLayoutModule->listingsED->setText(toqstr(lstparams)); if (!params.options.empty()) { latexModule->optionsLE->setText( diff --git a/src/frontends/qt4/QDocument.h b/src/frontends/qt4/QDocument.h index 4d1c6fe8fb..25e55b433f 100644 --- a/src/frontends/qt4/QDocument.h +++ b/src/frontends/qt4/QDocument.h @@ -68,6 +68,7 @@ public: public Q_SLOTS: void updateNumbering(); void change_adaptor(); + void validate_listings_params(); void saveDefaultClicked(); void useDefaultsClicked(); diff --git a/src/frontends/qt4/QInclude.cpp b/src/frontends/qt4/QInclude.cpp index 130fadce00..283dda8389 100644 --- a/src/frontends/qt4/QInclude.cpp +++ b/src/frontends/qt4/QInclude.cpp @@ -21,6 +21,7 @@ #include "LyXRC.h" +#include "insets/InsetListingsParams.h" #include "controllers/ControlInclude.h" #include @@ -57,6 +58,8 @@ QIncludeDialog::QIncludeDialog(QInclude * form) connect(typeCO, SIGNAL(activated(int)), this, SLOT(change_adaptor())); connect(typeCO, SIGNAL(activated(int)), this, SLOT(typeChanged(int))); connect(previewCB, SIGNAL(clicked()), this, SLOT(change_adaptor())); + connect(listingsED, SIGNAL(textChanged()), this, SLOT(change_adaptor())); + connect(listingsED, SIGNAL(textChanged()), this, SLOT(validate_listings_params())); filenameED->setValidator(new PathValidator(true, filenameED)); setFocusProxy(filenameED); @@ -75,6 +78,26 @@ void QIncludeDialog::change_adaptor() } +void QIncludeDialog::validate_listings_params() +{ + static bool isOK = true; + try { + InsetListingsParams par(fromqstr(listingsED->toPlainText())); + if (!isOK) { + isOK = true; + // listingsTB->setTextColor("black"); + listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters."); + okPB->setEnabled(true); + } + } catch (invalidParam & e) { + isOK = false; + // listingsTB->setTextColor("red"); + listingsTB->setPlainText(e.what()); + okPB->setEnabled(false); + } +} + + void QIncludeDialog::closeEvent(QCloseEvent * e) { form_->slotWMHide(); @@ -91,18 +114,32 @@ void QIncludeDialog::typeChanged(int v) visiblespaceCB->setChecked(false); previewCB->setEnabled(false); previewCB->setChecked(false); + listingsGB->setEnabled(false); + listingsED->setEnabled(false); break; //case Input case 1: visiblespaceCB->setEnabled(false); visiblespaceCB->setChecked(false); previewCB->setEnabled(true); + listingsGB->setEnabled(false); + listingsED->setEnabled(false); + break; + //case listings + case 3: + visiblespaceCB->setEnabled(false); + visiblespaceCB->setChecked(false); + previewCB->setEnabled(false); + listingsGB->setEnabled(true); + listingsED->setEnabled(true); break; //case Verbatim default: visiblespaceCB->setEnabled(true); previewCB->setEnabled(false); previewCB->setChecked(false); + listingsGB->setEnabled(false); + listingsED->setEnabled(false); break; } } @@ -145,6 +182,8 @@ void QInclude::build_dialog() bcview().addReadOnly(dialog_->browsePB); bcview().addReadOnly(dialog_->visiblespaceCB); bcview().addReadOnly(dialog_->typeCO); + bcview().addReadOnly(dialog_->listingsED); + dialog_->listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters."); addCheckedLineEdit(bcview(), dialog_->filenameED, dialog_->filenameLA); } @@ -164,11 +203,14 @@ void QInclude::update_contents() dialog_->visiblespaceCB->setEnabled(false); dialog_->previewCB->setChecked(false); dialog_->previewCB->setEnabled(false); + dialog_->listingsGB->setEnabled(false); + dialog_->listingsED->setEnabled(false); string cmdname = controller().params().getCmdName(); if (cmdname != "include" && cmdname != "verbatiminput" && - cmdname != "verbatiminput*") + cmdname != "verbatiminput*" && + cmdname != "lstinputlisting") cmdname = "input"; if (cmdname == "include") { @@ -187,7 +229,14 @@ void QInclude::update_contents() } else if (cmdname == "verbatiminput") { dialog_->typeCO->setCurrentIndex(2); dialog_->visiblespaceCB->setEnabled(true); - } + + } else if (cmdname == "lstinputlisting") { + dialog_->typeCO->setCurrentIndex(3); + dialog_->listingsGB->setEnabled(true); + dialog_->listingsED->setEnabled(true); + InsetListingsParams par(params.getOptions()); + dialog_->listingsED->setText(toqstr(par.separatedParams())); + } } @@ -199,15 +248,22 @@ void QInclude::apply() params.preview(dialog_->previewCB->isChecked()); int const item = dialog_->typeCO->currentIndex(); - if (item == 0) + if (item == 0) { params.setCmdName("include"); - else if (item == 1) + params.setOptions(string()); + } else if (item == 1) { params.setCmdName("input"); - else { + params.setOptions(string()); + } else if (item == 3) { + params.setCmdName("lstinputlisting"); + // the parameter string should have passed validation + params.setOptions(InsetListingsParams(fromqstr(dialog_->listingsED->toPlainText())).params()); + } else { if (dialog_->visiblespaceCB->isChecked()) params.setCmdName("verbatiminput*"); else params.setCmdName("verbatiminput"); + params.setOptions(string()); } controller().setParams(params); } @@ -222,8 +278,10 @@ void QInclude::browse() type = ControlInclude::INCLUDE; else if (item == 1) type = ControlInclude::INPUT; - else + else if (item == 2) type = ControlInclude::VERBATIM; + else + type = ControlInclude::LISTINGS; docstring const & name = controller().browse(qstring_to_ucs4(dialog_->filenameED->text()), type); diff --git a/src/frontends/qt4/QInclude.h b/src/frontends/qt4/QInclude.h index dd68e7584d..bc7244058d 100644 --- a/src/frontends/qt4/QInclude.h +++ b/src/frontends/qt4/QInclude.h @@ -33,6 +33,7 @@ public: virtual void show(); protected Q_SLOTS: virtual void change_adaptor(); + void validate_listings_params(); virtual void loadClicked(); virtual void browseClicked(); virtual void typeChanged(int v); diff --git a/src/frontends/qt4/QListings.cpp b/src/frontends/qt4/QListings.cpp new file mode 100644 index 0000000000..7df97e1870 --- /dev/null +++ b/src/frontends/qt4/QListings.cpp @@ -0,0 +1,137 @@ +/** + * \file QListings.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "QListings.h" +#include "Qt2BC.h" +#include "qt_helpers.h" +#include "controllers/ControlListings.h" +#include "insets/InsetListingsParams.h" +#include "debug.h" + +#include "support/convert.h" +#include "support/lstrings.h" + +#include +#include +#include + + +using std::string; + +namespace lyx { +namespace frontend { + +///////////////////////////////////////////////////////////////////// +// +// QListingsDialog +// +///////////////////////////////////////////////////////////////////// + + +QListingsDialog::QListingsDialog(QListings * form) + : form_(form) +{ + setupUi(this); + + connect(okPB, SIGNAL(clicked()), form, SLOT(slotOK())); + connect(closePB, SIGNAL(clicked()), form, SLOT(slotClose())); + connect(inlineCB, SIGNAL(clicked()), this, SLOT(change_adaptor())); + connect(listingsED, SIGNAL(textChanged()), this, SLOT(change_adaptor())); + connect(listingsED, SIGNAL(textChanged()), this, SLOT(validate_listings_params())); +} + + +void QListingsDialog::closeEvent(QCloseEvent * e) +{ + form_->slotWMHide(); + e->accept(); +} + + +void QListingsDialog::change_adaptor() +{ + form_->changed(); +} + + +void QListingsDialog::validate_listings_params() +{ + static bool isOK = true; + try { + InsetListingsParams par(fromqstr(listingsED->toPlainText())); + if (!isOK) { + isOK = true; + // listingsTB->setTextColor("black"); + listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters."); + okPB->setEnabled(true); + } + } catch (invalidParam & e) { + isOK = false; + // listingsTB->setTextColor("red"); + listingsTB->setPlainText(e.what()); + okPB->setEnabled(false); + } +} + +///////////////////////////////////////////////////////////////////// +// +// QListings +// +///////////////////////////////////////////////////////////////////// + +typedef QController > wrap_base_class; + +QListings::QListings(Dialog & parent) + : wrap_base_class(parent, _("Program Listings Settings")) +{ +} + + +void QListings::build_dialog() +{ + dialog_.reset(new QListingsDialog(this)); + + bcview().setOK(dialog_->okPB); + bcview().setCancel(dialog_->closePB); + dialog_->listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters."); + + update_contents(); +} + + +/// not used right now. +void QListings::apply() +{ + InsetListingsParams & params = controller().params(); + params.setInline(dialog_->inlineCB->isChecked()); + params.setParams(fromqstr(dialog_->listingsED->toPlainText())); + controller().setParams(params); +} + + +void QListings::update_contents() +{ + InsetListingsParams & params = controller().params(); + dialog_->listingsED->setText(toqstr(params.separatedParams())); + + if (params.isInline()) + dialog_->inlineCB->setChecked(true); + else + dialog_->inlineCB->setChecked(false); +} + + +} // namespace frontend +} // namespace lyx + + +#include "QListings_moc.cpp" diff --git a/src/frontends/qt4/QListings.h b/src/frontends/qt4/QListings.h new file mode 100644 index 0000000000..6d0edfcc1b --- /dev/null +++ b/src/frontends/qt4/QListings.h @@ -0,0 +1,61 @@ +// -*- C++ -*- +/** + * \file QListings.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef QLISTINGS_H +#define QLISTINGS_H + +#include "QDialogView.h" +#include "ui/ListingsUi.h" + +#include +#include + +namespace lyx { +namespace frontend { + +class QListings; + +class QListingsDialog : public QDialog, public Ui::QListingsUi { + Q_OBJECT +public: + QListingsDialog(QListings * form); +protected Q_SLOTS: + virtual void change_adaptor(); + /// AFAIK, QValidator only works for QLineEdit so + /// I have to validate listingsED (QTextEdit) manually. + void validate_listings_params(); +protected: + virtual void closeEvent(QCloseEvent * e); +private: + QListings * form_; +}; + + +class ControlListings; + +class QListings : public QController > { +public: + friend class QListingsDialog; + + QListings(Dialog &); +private: + /// Apply changes + virtual void apply(); + /// update + virtual void update_contents(); + /// build the dialog + virtual void build_dialog(); +}; + +} // namespace frontend +} // namespace lyx + +#endif // QLISTINGS_H diff --git a/src/frontends/qt4/ui/IncludeUi.ui b/src/frontends/qt4/ui/IncludeUi.ui index 704c8b5b18..1a4f52ea08 100644 --- a/src/frontends/qt4/ui/IncludeUi.ui +++ b/src/frontends/qt4/ui/IncludeUi.ui @@ -5,8 +5,8 @@ 0 0 - 386 - 171 + 416 + 373 @@ -15,194 +15,325 @@ true - - - 9 + + + + 9 + 9 + 401 + 361 + - - 6 - - - - - - 3 - 0 - 0 - 0 - - - - Show LaTeX preview - - - &Show preview - - - - - - - - 3 - 0 - 0 - 0 - - - - Underline spaces in generated output - - - &Mark spaces in output - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 130 - 50 - - - - - - - - File name to include - - - - - - - Load the file - - - &Load - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 28 - 28 - - - - - - - - - Include + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + + + + &File: + + + filenameED + + + + + + + File name to include + + + + + + + + + 0 + + + 6 + + + + + &Include Type: + + + typeCO + + + + + + + + Include + + + + + Input + + + + + Verbatim + + + + + Listings + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 28 + 28 + + + + + + + + + + + + 0 + + + 6 + + + + + Select a file + + + &Browse... + + + + + + + Load the file + + + &Load + + + + + + + + + + + 0 + + + 6 - - - - Input + + + + + + + + + 10 + 20 + 100 + 23 + + + + + 3 + 0 + 0 + 0 + + + + Show LaTeX preview + + + &Show preview + + + + + + 10 + 50 + 142 + 23 + + + + + 3 + 0 + 0 + 0 + + + + Underline spaces in generated output + + + &Mark spaces in output + + + + + + + + Listing Params + + + + + 10 + 100 + 171 + 121 + + + + + + + 10 + 20 + 171 + 71 + + + + + 4 + 0 + 0 + 0 + + + + 14 + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + false + + + + + + + + + + 0 - - - - Verbatim + + 6 - - - - - - - &Include Type: - - - typeCO - - - - - - - Select a file - - - &Browse... - - - - - - - - - - &File: - - - filenameED - - - - - - - 0 - - - 6 - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - &OK - - - true - - - - - - - &Close - - - - - - + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &OK + + + true + + + + + + + &Close + + + + + + + filenameED diff --git a/src/frontends/qt4/ui/ListingsUi.ui b/src/frontends/qt4/ui/ListingsUi.ui new file mode 100644 index 0000000000..6ebfee0e13 --- /dev/null +++ b/src/frontends/qt4/ui/ListingsUi.ui @@ -0,0 +1,160 @@ + + QListingsUi + + + Qt::ApplicationModal + + + + 0 + 0 + 451 + 392 + + + + Listing + + + true + + + + + 10 + 10 + 431 + 371 + + + + + 0 + + + 6 + + + + + Inlined listing (\lstinline) + + + + + + + + 7 + 7 + 0 + 0 + + + + Parameters + + + + + 10 + 100 + 411 + 171 + + + + + + + 10 + 20 + 411 + 71 + + + + + 4 + 0 + 0 + 0 + + + + 14 + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + false + + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 101 + 27 + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + okPB + closePB + + + qt_helpers.h + + + + diff --git a/src/frontends/qt4/ui/TextLayoutUi.ui b/src/frontends/qt4/ui/TextLayoutUi.ui index cf3af16043..aca743200a 100644 --- a/src/frontends/qt4/ui/TextLayoutUi.ui +++ b/src/frontends/qt4/ui/TextLayoutUi.ui @@ -1,202 +1,316 @@ - - - TextLayoutUi 0 0 - 287 - 208 + 449 + 517 - - - 9 + + + + 9 + 10 + 399 + 511 + - - 6 - - - - - false - - - - 1 - 0 - 0 - 0 - - - - - - - - - 5 - 0 - 0 - 0 - - - - false - - - - - - - &Line spacing: - - - lspacingCO - - - - - - - Separate Paragraphs With - - - - 9 + + + 0 + + + 6 + + + + + Separate Paragraphs With + + + + 9 + + + 6 + + + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 178 + 22 + + + + + + + + false + + + + + + + false + + + + 1 + 0 + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 31 + 58 + + + + + + + + + + + &Vertical space + + + + + + + Indent consecutive paragraphs + + + &Indentation + + + + + + + + + + Spacing + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + &Line spacing: + + + lspacingCO + + + + + + + + 5 + 0 + 0 + 0 + + + + false + + + + + + + false + + + + 1 + 0 + 0 + 0 + + + + + + + + + + Format text into two columns + + + Two-&column document + + + + + + + + + + + + + 7 + 0 + 0 + 0 + + + + + 0 + 150 + + + + Qt::LeftToRight + + + Listings settings + + + + + 10 + 70 + 371 + 71 + + + + + 4 + 0 + 0 + 0 + + + + 14 + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + false + + + + + + 10 + 20 + 371 + 75 + + + + + 7 + 0 + 0 + 0 + + + + + + + + + Qt::Vertical - - 6 + + QSizePolicy::Expanding - - - - false - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 178 - 22 - - - - - - - - false - - - - - - - false - - - - 1 - 0 - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 31 - 58 - - - - - - - - - - - &Vertical space - - - - - - - Indent consecutive paragraphs - - - &Indentation - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Format text into two columns - - - Two-&column document - - - - + + + 397 + 27 + + + + + + - - - qt_helpers.h - LengthCombo QWidget
LengthCombo.h
- 0 -
@@ -208,6 +322,9 @@ lspacingLE twoColumnCB + + qt_helpers.h +
diff --git a/src/insets/Inset.cpp b/src/insets/Inset.cpp index 9dd710d0ad..93b749e5d8 100644 --- a/src/insets/Inset.cpp +++ b/src/insets/Inset.cpp @@ -99,6 +99,7 @@ static TranslatorMap const build_translator() InsetName("charstyle", Inset::CHARSTYLE_CODE), InsetName("vspace", Inset::VSPACE_CODE), InsetName("mathmacroarg", Inset::MATHMACROARG_CODE), + InsetName("listings", Inset::LISTINGS_CODE), }; std::size_t const insetnames_size = diff --git a/src/insets/Inset.h b/src/insets/Inset.h index e446158bd6..3eb44fedaa 100644 --- a/src/insets/Inset.h +++ b/src/insets/Inset.h @@ -348,7 +348,9 @@ public: /// NOMENCL_PRINT_CODE, /// - PAGEBREAK_CODE + PAGEBREAK_CODE, + /// + LISTINGS_CODE }; /** returns the Code corresponding to the \c name. diff --git a/src/insets/InsetCommandParams.cpp b/src/insets/InsetCommandParams.cpp index df7ce6f547..8b6b827412 100644 --- a/src/insets/InsetCommandParams.cpp +++ b/src/insets/InsetCommandParams.cpp @@ -113,6 +113,13 @@ InsetCommandParams::findInfo(std::string const & name) return &info; } + if (name == "lstinputlisting") { + static const char * const paramnames[] = {"filename", "lstparams", ""}; + static const bool isoptional[] = {false, true}; + static const CommandInfo info = {2, paramnames, isoptional}; + return &info; + } + // InsetIndex, InsetPrintIndex, InsetLabel if (name == "index" || name == "printindex" || name == "label") { static const char * const paramnames[] = {"name", ""}; diff --git a/src/insets/InsetCommandParams.h b/src/insets/InsetCommandParams.h index 7d137424d4..3e6b20eca8 100644 --- a/src/insets/InsetCommandParams.h +++ b/src/insets/InsetCommandParams.h @@ -38,9 +38,9 @@ public: docstring const getCommand() const; /// Return the command name std::string const & getCmdName() const { return name_; } -private: - /// FIXME remove + /// this is used by listings package. std::string const getOptions() const; +private: /// FIXME remove std::string const getSecOptions() const; public: @@ -50,9 +50,9 @@ public: /// are cleared except those that exist also in the new command. /// What matters here is the parameter name, not position. void setCmdName(std::string const & n); -private: - /// FIXME remove + /// this is used by the listings package void setOptions(std::string const &); +private: /// FIXME remove void setSecOptions(std::string const &); public: diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index 2ad17d3072..27254975dd 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -39,6 +39,7 @@ #include "graphics/PreviewLoader.h" #include "insets/RenderPreview.h" +#include "insets/InsetListingsParams.h" #include "support/filetools.h" #include "support/lstrings.h" // contains @@ -179,7 +180,8 @@ enum Types { INCLUDE = 0, VERB = 1, INPUT = 2, - VERBAST = 3 + VERBAST = 3, + LISTINGS = 4, }; @@ -193,6 +195,8 @@ Types type(InsetCommandParams const & params) return VERB; if (command_name == "verbatiminput*") return VERBAST; + if (command_name == "lstinputlisting") + return LISTINGS; return INCLUDE; } @@ -205,6 +209,12 @@ bool isVerbatim(InsetCommandParams const & params) } +bool isListings(InsetCommandParams const & params) +{ + return params.getCmdName() == "lstinputlisting"; +} + + string const masterFilename(Buffer const & buffer) { return buffer.getMasterBuffer()->fileName(); @@ -311,6 +321,9 @@ docstring const InsetInclude::getScreenLabel(Buffer const & buf) const case INCLUDE: temp += buf.B_("Include"); break; + case LISTINGS: + temp += buf.B_("Program Listing"); + break; } temp += ": "; @@ -329,7 +342,7 @@ namespace { /// return the child buffer if the file is a LyX doc and is loaded Buffer * getChildBuffer(Buffer const & buffer, InsetCommandParams const & params) { - if (isVerbatim(params)) + if (isVerbatim(params) || isListings(params)) return 0; string const included_file = includedFilename(buffer, params).absFilename(); @@ -343,7 +356,7 @@ Buffer * getChildBuffer(Buffer const & buffer, InsetCommandParams const & params /// return true if the file is or got loaded. bool loadIfNeeded(Buffer const & buffer, InsetCommandParams const & params) { - if (isVerbatim(params)) + if (isVerbatim(params) || isListings(params)) return false; FileName const included_file = includedFilename(buffer, params); @@ -478,6 +491,14 @@ int InsetInclude::latex(Buffer const & buffer, odocstream & os, os << '\\' << from_ascii(params_.getCmdName()) << '{' << from_utf8(incfile) << '}'; } + } else if (type(params_) == LISTINGS) { + os << '\\' << from_ascii(params_.getCmdName()); + string opt = params_.getOptions(); + // opt is set in QInclude dialog and should have passed validation. + InsetListingsParams params(opt); + if (!params.params().empty()) + os << "[" << from_utf8(params.encodedString()) << "]"; + os << '{' << from_utf8(incfile) << '}'; } else { runparams.exportdata->addExternalFile(tex_format, writefile, exportfile); @@ -498,7 +519,7 @@ int InsetInclude::latex(Buffer const & buffer, odocstream & os, int InsetInclude::plaintext(Buffer const & buffer, odocstream & os, OutputParams const &) const { - if (isVerbatim(params_)) { + if (isVerbatim(params_) || isListings(params_)) { os << '[' << getScreenLabel(buffer) << '\n'; // FIXME: We don't know the encoding of the file docstring const str = @@ -550,7 +571,7 @@ int InsetInclude::docbook(Buffer const & buffer, odocstream & os, runparams.exportdata->addExternalFile("docbook-xml", writefile, exportfile); - if (isVerbatim(params_)) { + if (isVerbatim(params_) || isListings(params_)) { os << ""; @@ -575,7 +596,7 @@ void InsetInclude::validate(LaTeXFeatures & features) const else writefile = included_file; - if (!features.runparams().nice && !isVerbatim(params_)) { + if (!features.runparams().nice && !isVerbatim(params_) && !isListings(params_)) { incfile = DocFileName(writefile).mangledFilename(); writefile = makeAbsPath(incfile, buffer.getMasterBuffer()->temppath()).absFilename(); @@ -585,6 +606,8 @@ void InsetInclude::validate(LaTeXFeatures & features) const if (isVerbatim(params_)) features.require("verbatim"); + else if (isListings(params_)) + features.require("listings"); // Here we must do the fun stuff... // Load the file in the include if it needs diff --git a/src/insets/InsetListings.cpp b/src/insets/InsetListings.cpp new file mode 100644 index 0000000000..59b289a8ff --- /dev/null +++ b/src/insets/InsetListings.cpp @@ -0,0 +1,285 @@ +/** + * \file InsetListings.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetListings.h" + +#include "Language.h" +#include "gettext.h" +#include "DispatchResult.h" +#include "FuncRequest.h" +#include "FuncStatus.h" +#include "Cursor.h" +#include "support/lstrings.h" + +#include + +namespace lyx { + +using support::token; + +using std::auto_ptr; +using std::istringstream; +using std::ostream; +using std::ostringstream; +using std::string; + + +void InsetListings::init() +{ + // FIXME: define Color::listing? + Font font(Font::ALL_SANE); + font.decSize(); + font.decSize(); + font.setColor(Color::foreground); + setLabelFont(font); + // FIXME: english_language? + text_.current_font.setLanguage(english_language); + text_.real_current_font.setLanguage(english_language); + // FIXME: why I can not make text of source code black with the following two lines? + text_.current_font.setColor(Color::foreground); + text_.real_current_font.setColor(Color::foreground); +} + + +InsetListings::InsetListings(BufferParams const & bp, InsetListingsParams const & par) + : InsetERT(bp, par.status()) +{ + init(); +} + + +InsetListings::InsetListings(InsetListings const & in) + : InsetERT(in) +{ + init(); +} + + +auto_ptr InsetListings::doClone() const +{ + return auto_ptr(new InsetListings(*this)); +} + + +InsetListings::~InsetListings() +{ + InsetListingsMailer(*this).hideDialog(); +} + + +bool InsetListings::display() const +{ + return !params().isInline(); +} + + +void InsetListings::write(Buffer const & buf, ostream & os) const +{ + os << "listings" << "\n"; + InsetListingsParams const & par = params(); + // parameter string is encoded to be a valid lyx token. + string opt = par.encodedString(); + if (!opt.empty()) + os << "lstparams \"" << opt << "\"\n"; + if (par.isInline()) + os << "inline true\n"; + else + os << "inline false\n"; + InsetCollapsable::write(buf, os); +} + + +void InsetListings::read(Buffer const & buf, Lexer & lex) +{ + while (lex.isOK()) { + lex.next(); + string const token = lex.getString(); + if (token == "lstparams") { + lex.next(); + string const value = lex.getString(); + params().fromEncodedString(value); + } else if (token == "inline") { + lex.next(); + params().setInline(lex.getBool()); + } else { + // no special option, push back 'status' etc + lex.pushToken(token); + break; + } + } + InsetCollapsable::read(buf, lex); +} + + +docstring const InsetListings::editMessage() const +{ + return _("Opened Listings Inset"); +} + + +int InsetListings::latex(Buffer const &, odocstream & os, + OutputParams const &) const +{ + string param_string = params().encodedString(); + // NOTE: I use {} to quote text, which is an experimental feature + // of the listings package (see page 25 of the manual) + int lines = 0; + bool lstinline = params().isInline(); + if (lstinline) { + if (param_string.empty()) + os << "\\lstinline{"; + else + os << "\\lstinline[" << from_ascii(param_string) << "]{"; + } else { + if (param_string.empty()) + os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}\n"; + else + os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}[" << from_ascii(param_string) << "]\n"; + lines += 4; + } + ParagraphList::const_iterator par = paragraphs().begin(); + ParagraphList::const_iterator end = paragraphs().end(); + + while (par != end) { + pos_type siz = par->size(); + for (pos_type i = 0; i < siz; ++i) { + // ignore all struck out text + if (par->isDeleted(i)) + continue; + os.put(par->getChar(i)); + } + ++par; + // for the inline case, if there are multiple paragraphs + // they are simply joined. Otherwise, expect latex errors. + if (par != end && !lstinline) { + os << "\n"; + ++lines; + } + } + if (lstinline) + os << "}"; + else { + os << "\n\\end{lstlisting}\n\\endgroup\n"; + lines += 3; + } + + return lines; +} + + +void InsetListings::doDispatch(Cursor & cur, FuncRequest & cmd) +{ + switch (cmd.action) { + + case LFUN_INSET_MODIFY: { + InsetListingsMailer::string2params(to_utf8(cmd.argument()), params()); + break; + } + case LFUN_INSET_DIALOG_UPDATE: + InsetListingsMailer(*this).updateDialog(&cur.bv()); + break; + case LFUN_MOUSE_RELEASE: { + if (cmd.button() == mouse_button::button3 && hitButton(cmd)) { + InsetListingsMailer(*this).showDialog(&cur.bv()); + break; + } + InsetERT::doDispatch(cur, cmd); + break; + } + default: + InsetERT::doDispatch(cur, cmd); + break; + } +} + + +bool InsetListings::getStatus(Cursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action) { + case LFUN_INSET_DIALOG_UPDATE: + status.enabled(true); + return true; + default: + return InsetERT::getStatus(cur, cmd, status); + } +} + + +void InsetListings::setButtonLabel() +{ + // FIXME UNICODE + setLabel(isOpen() ? _("Listings") : getNewLabel(_("Listings"))); +} + + +void InsetListings::validate(LaTeXFeatures & features) const +{ + features.require("listings"); + InsetERT::validate(features); +} + + +bool InsetListings::showInsetDialog(BufferView * bv) const +{ + InsetListingsMailer(const_cast(*this)).showDialog(bv); + return true; +} + + +void InsetListings::getDrawFont(Font & font) const +{ + font = Font(Font::ALL_INHERIT, english_language); + font.setFamily(Font::TYPEWRITER_FAMILY); + font.setColor(Color::foreground); +} + + +string const InsetListingsMailer::name_("listings"); + +InsetListingsMailer::InsetListingsMailer(InsetListings & inset) + : inset_(inset) +{} + + +string const InsetListingsMailer::inset2string(Buffer const &) const +{ + return params2string(inset_.params()); +} + + +void InsetListingsMailer::string2params(string const & in, + InsetListingsParams & params) +{ + params = InsetListingsParams(); + if (in.empty()) + return; + istringstream data(in); + Lexer lex(0, 0); + lex.setStream(data); + // discard "listings", which is only used to determine inset + lex.next(); + params.read(lex); +} + + +string const +InsetListingsMailer::params2string(InsetListingsParams const & params) +{ + ostringstream data; + data << name_ << " "; + params.write(data); + return data.str(); +} + + +} // namespace lyx diff --git a/src/insets/InsetListings.h b/src/insets/InsetListings.h new file mode 100644 index 0000000000..1d02c7cd4f --- /dev/null +++ b/src/insets/InsetListings.h @@ -0,0 +1,99 @@ +// -*- C++ -*- +/** + * \file InsetListings.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef INSETLISTINGS_H +#define INSETLISTINGS_H + +#include "LaTeXFeatures.h" +#include "InsetERT.h" +#include "InsetListingsParams.h" +#include "MailInset.h" + + +namespace lyx { + +/** A collapsable text inset for program listings. + */ + + +class InsetListings : public InsetERT { +public: + /// + InsetListings(BufferParams const &, InsetListingsParams const & par = InsetListingsParams()); + /// + ~InsetListings(); + /// + Inset::Code lyxCode() const { return Inset::LISTINGS_CODE; } + /// lstinline is inlined, normal listing is displayed + virtual bool display() const; + /// + docstring name() const { return from_ascii("Listings"); } + /// + void write(Buffer const & buf, std::ostream & os) const; + /// + void read(Buffer const & buf, Lexer & lex); + /// + virtual docstring const editMessage() const; + /// + int latex(Buffer const &, odocstream &, OutputParams const &) const; + /// + void validate(LaTeXFeatures &) const; + /// + bool showInsetDialog(BufferView *) const; + /// + void getDrawFont(Font &) const; + /// + InsetListingsParams const & params() const { return params_; } + /// + InsetListingsParams & params() { return params_; } +protected: + InsetListings(InsetListings const &); + /// + virtual void doDispatch(Cursor & cur, FuncRequest & cmd); + /// + bool getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus &) const; +private: + virtual std::auto_ptr doClone() const; + /// + void init(); + /// + void setButtonLabel(); + /// + InsetListingsParams params_; +}; + + +class InsetListingsMailer : public MailInset { +public: + /// + InsetListingsMailer(InsetListings & inset); + /// + virtual Inset & inset() const { return inset_; } + /// + virtual std::string const & name() const { return name_; } + /// + virtual std::string const inset2string(Buffer const &) const; + /// + static void string2params(std::string const &, + InsetListingsParams &); + /// + static std::string const params2string(InsetListingsParams const &); +private: + /// + static std::string const name_; + /// + InsetListings & inset_; +}; + + +} // namespace lyx + +#endif diff --git a/src/insets/InsetListingsParams.cpp b/src/insets/InsetListingsParams.cpp new file mode 100644 index 0000000000..ef0bcae380 --- /dev/null +++ b/src/insets/InsetListingsParams.cpp @@ -0,0 +1,523 @@ +/** + * \file InsetListingsParams.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "Lexer.h" +#include "InsetListingsParams.h" + +#include "gettext.h" +#include "Length.h" + +#include +#include + +#include "support/lstrings.h" +#include "support/convert.h" + +using std::vector; +using std::ostream; +using std::string; +using std::exception; +using lyx::support::trim; + +namespace lyx +{ + +enum param_type { + ALL, + TRUEFALSE, + INTEGER, + LENGTH, + ONEOF, + SUBSETOF, +}; + + +/** Information about each parameter + */ +struct listings_param_info { + /// name of the parameter + char const * name; + /// default value + char const * value; + // for option with value "true", "false", + // if onoff is true, + // "true": option + // "false": + // "other": option="other" + // onoff is false, + // "true": option=true + // "false": option=false + bool onoff; + /// validator type + param_type type; + // ALL: + // TRUEFALSE: + // INTEGER: + // LENGTH: + // info is ignored. + // ONEOF + // info is a \n separated string with allowed values + // SUBSETOF + // info is a string from which par is composed of + // (e.g. floatplacement can be one or more of tbph) + char const * info; + // + char const * hint; +}; + + +char const * allowed_languages = + "no language\nBAP\nACSL\nAda\nALGOL\nC\nC++\nCaml\nClean\nCobol\n" + "Comal 80\ncsh\nDelphi\nEiffel\nElan\nEuphoria\nFortran\nHaskell\n" + "HTML\nIDL\nJava\nLisp\nLogo\nmake\nMathematica\nMatlab\nMercury\n" + "Miranda\nML\nModula-2\nOberon-2\nOCL\nPascal\nPerl\nPHP\nPL/I\nPOV\n" + "Python\nProlog\nR\nS\nSAS\nSHELXL\nSimula\ntcl\nSQL\nTeX\nVBScript\n" + "VHDL\nXML"; + +char const * style_hint = "Use \\footnotessize, \\small, \\itshape, \\ttfamily or something like that"; +char const * frame_hint = "none, leftline, topline, bottomline, lines, single, shadowbox or subset of trblTRBL"; +char const * frameround_hint = "The foru letters (t or f) attached to top right, bottom right, bottom left and top left corner."; +char const * color_hint = "Enter something like \\color{white}"; + +/// options copied from page 26 of listings manual +// FIXME: add default parameters ... (which is not used now) +listings_param_info const listings_param_table[] = { + { "float", "false", true, SUBSETOF, "tbph", "" }, + { "floatplacement", "tbp", false, SUBSETOF, "tbph", "" }, + { "aboveskip", "\\medskipamount", false, LENGTH, "", "" }, + { "belowskip", "\\medskipamount", false, LENGTH, "", "" }, + { "lineskip", "", false, LENGTH, "", "" }, + { "boxpos", "", false, SUBSETOF, "bct", "" }, + { "print", "", false, TRUEFALSE, "", "" }, + { "firstline", "", false, INTEGER, "", "" }, + { "lastline", "", false, INTEGER, "", "" }, + { "showlines", "", false, TRUEFALSE, "", "" }, + { "emptylines", "", false, ALL, "", "Expect a number with an optional * before it" }, + { "gobble", "", false, INTEGER, "", "" }, + { "style", "", false, ALL, "", "" }, + { "language", "", false, ONEOF, allowed_languages, "" }, + { "alsolanguage", "", false, ONEOF, allowed_languages, "" }, + { "defaultdialect", "", false, ONEOF, allowed_languages, "" }, + { "printpod", "", false, TRUEFALSE, "", "" }, + { "usekeywordsintag", "", false, TRUEFALSE, "", "" }, + { "tagstyle", "", false, ALL, "", style_hint }, + { "markfirstintag", "", false, ALL, "", style_hint }, + { "makemacrouse", "", false, TRUEFALSE, "", "" }, + { "basicstyle", "", false, ALL, "", style_hint }, + { "identifierstyle", "", false, ALL, "", style_hint }, + { "commentstyle", "", false, ALL, "", style_hint }, + { "stringstyle", "", false, ALL, "", style_hint }, + { "keywordstyle", "", false, ALL, "", style_hint }, + { "ndkeywordstyle", "", false, ALL, "", style_hint }, + { "classoffset", "", false, INTEGER, "", "" }, + { "texcsstyle", "", false, ALL, "", style_hint }, + { "directivestyle", "", false, ALL, "", style_hint }, + { "emph", "", false, ALL, "", "" }, + { "moreemph", "", false, ALL, "", "" }, + { "deleteemph", "", false, ALL, "", "" }, + { "emphstyle", "", false, ALL, "", "" }, + { "delim", "", false, ALL, "", "" }, + { "moredelim", "", false, ALL, "", "" }, + { "deletedelim", "", false, ALL, "", "" }, + { "extendedchars", "", false, TRUEFALSE, "", "" }, + { "inputencoding", "", false, ALL, "", "" }, + { "upquote", "", false, TRUEFALSE, "", "" }, + { "tabsize", "", false, INTEGER, "", "" }, + { "showtabs", "", false, ALL, "", "" }, + { "tab", "", false, ALL, "", "" }, + { "showspaces", "", false, TRUEFALSE, "", "" }, + { "showstringspaces", "", false, TRUEFALSE, "", "" }, + { "formfeed", "", false, ALL, "", "" }, + { "numbers", "", false, ONEOF, "none\nleft\nright", "" }, + { "stepnumber", "", false, INTEGER, "", "" }, + { "numberfirstline", "", false, TRUEFALSE, "", "" }, + { "numberstyle", "", false, ALL, "", style_hint }, + { "numbersep", "", false, LENGTH, "", "" }, + { "numberblanklines", "", false, ALL, "", "" }, + { "firstnumber", "", false, ALL, "", "auto, last or a number" }, + { "name", "", false, ALL, "", "" }, + { "thelstnumber", "", false, ALL, "", "" }, + { "title", "", false, ALL, "", "" }, + { "caption", "", false, ALL, "", "" }, + { "label", "", false, ALL, "", "" }, + { "nolol", "", false, TRUEFALSE, "", "" }, + { "captionpos", "", false, SUBSETOF, "tb", "" }, + { "abovecaptionskip", "", false, LENGTH, "", "" }, + { "belowcaptionskip", "", false, LENGTH, "", "" }, + { "linewidth", "", false, LENGTH, "", "" }, + { "xleftmargin", "", false, LENGTH, "", "" }, + { "xrightmargin", "", false, LENGTH, "", "" }, + { "resetmargin", "", false, TRUEFALSE, "", "" }, + { "breaklines", "", false, TRUEFALSE, "", "" }, + { "prebreak", "", false, ALL, "", "" }, + { "postbreak", "", false, ALL, "", "" }, + { "breakindent", "", false, LENGTH, "", "" }, + { "breakautoindent", "", false, TRUEFALSE, "", "" }, + { "frame", "", false, ALL, "", frame_hint }, + { "frameround", "", false, SUBSETOF, "tf", frameround_hint }, + { "framesep", "", false, LENGTH, "", "" }, + { "rulesep", "", false, LENGTH, "", "" }, + { "framerule", "", false, LENGTH, "", "" }, + { "framexleftmargin", "", false, LENGTH, "", "" }, + { "framexrightmargin", "", false, LENGTH, "", "" }, + { "framextopmargin", "", false, LENGTH, "", "" }, + { "framexbottommargin", "", false, LENGTH, "", "" }, + { "backgroundcolor", "", false, ALL, "", color_hint }, + { "rulecolor", "", false, ALL, "", color_hint }, + { "fillcolor", "", false, ALL, "", color_hint }, + { "rulesepcolor", "", false, ALL, "", color_hint }, + { "frameshape", "", false, ALL, "", "" }, + { "index", "", false, ALL, "", "" }, + { "moreindex", "", false, ALL, "", "" }, + { "deleteindex", "", false, ALL, "", "" }, + { "indexstyle", "", false, ALL, "", "" }, + { "columns", "", false, ALL, "", "" }, + { "flexiblecolumns", "", false, ALL, "", "" }, + { "keepspaces", "", false, TRUEFALSE, "", "" }, + { "basewidth", "", false, LENGTH, "", "" }, + { "fontadjust", "", true, TRUEFALSE, "", "" }, + { "texcl", "", false, TRUEFALSE, "", "" }, + { "mathescape", "", false, TRUEFALSE, "", "" }, + { "escapechar", "", false, ALL, "", "" }, + { "escapeinside", "", false, ALL, "", "" }, + { "escepeinside", "", false, ALL, "", "" }, + { "escepebegin", "", false, ALL, "", "" }, + { "escepeend", "", false, ALL, "", "" }, + { "fancyvrb", "", false, TRUEFALSE, "", "" }, + { "fvcmdparams", "", false, ALL, "", "" }, + { "morefvcmdparams", "", false, ALL, "", "" }, + { "keywordsprefix", "", false, ALL, "", "" }, + { "keywords", "", false, ALL, "", "" }, + { "morekeywords", "", false, ALL, "", "" }, + { "deletekeywords", "", false, ALL, "", "" }, + { "ndkeywords", "", false, ALL, "", "" }, + { "morendkeywords", "", false, ALL, "", "" }, + { "deletendkeywords", "", false, ALL, "", "" }, + { "texcs", "", false, ALL, "", "" }, + { "moretexcs", "", false, ALL, "", "" }, + { "deletetexcs", "", false, ALL, "", "" }, + { "directives", "", false, ALL, "", "" }, + { "moredirectives", "", false, ALL, "", "" }, + { "deletedirectives", "", false, ALL, "", "" }, + { "sensitive", "", false, ALL, "", "" }, + { "alsoletter", "", false, ALL, "", "" }, + { "alsodigit", "", false, ALL, "", "" }, + { "alsoother", "", false, ALL, "", "" }, + { "otherkeywords", "", false, ALL, "", "" }, + { "tag", "", false, ALL, "", "" }, + { "string", "", false, ALL, "", "" }, + { "morestring", "", false, ALL, "", "" }, + { "deletestring", "", false, ALL, "", "" }, + { "comment", "", false, ALL, "", "" }, + { "morecomment", "", false, ALL, "", "" }, + { "deletecomment", "", false, ALL, "", "" }, + { "keywordcomment", "", false, ALL, "", "" }, + { "morekeywordcomment", "", false, ALL, "", "" }, + { "deletekeywordcomment", "", false, ALL, "", "" }, + { "keywordcommentsemicolon", "", false, ALL, "", "" }, + { "podcomment", "", false, ALL, "", "" }, + { "", "", false, ALL, "", ""} +}; + + +class parValidator +{ +public: + parValidator(string const & name); + + /// validate given parameter + /// invalidParam will be thrown if invalid + /// parameter is found. + void validate(std::string const & par) const; + +private: + /// parameter name + string const & name; + /// + listings_param_info const * info; +}; + + +parValidator::parValidator(string const & n) + : name(n), info(0) +{ + if (name.empty()) + throw invalidParam("Invalid (empty) listings param name."); + else if (name == "?") { + string pars; + size_t idx = 0; + while (listings_param_table[idx].name != string()) { + if (!pars.empty()) + pars += ", "; + pars += listings_param_table[idx].name; + ++idx; + } + throw invalidParam("Available listings parameters are " + pars); + } + // locate name in parameter table + size_t idx = 0; + while (listings_param_table[idx].name != name && listings_param_table[idx].name != string()) + ++idx; + // found the name + if (listings_param_table[idx].name != "") { + info = &listings_param_table[idx]; + return; + } + // otherwise, produce a meaningful error message. + string matching_names; + for (size_t i = 0; i < idx; ++i) { + string n(listings_param_table[i].name); + if (n.size() >= name.size() && n.substr(0, name.size()) == name) { + if (matching_names.empty()) + matching_names += n; + else + matching_names += ", " + n; + } + } + if (matching_names.empty()) + throw invalidParam("Unknown listings param name: " + name); + else + throw invalidParam("Parameters starting with '" + name + + "': " + matching_names); +} + + +void parValidator::validate(std::string const & par) const +{ + switch (info->type) { + case ALL: + if (par.empty() && !info->onoff) { + if (info->hint != "") + throw invalidParam(info->hint); + else + throw invalidParam("An value is expected"); + } + return; + case TRUEFALSE: { + if (par.empty() && !info->onoff) { + if (info->hint != "") + throw invalidParam(info->hint); + else + throw invalidParam("Please specify true or false"); + } + if (par != "true" && par != "false") + throw invalidParam("Only true or false is allowed for parameter" + name); + return; + } + case INTEGER: { + if (par.empty() && !info->onoff) { + if (info->hint != "") + throw invalidParam(info->hint); + else + throw invalidParam("Please specify an integer value"); + } + if (convert(par) == 0 && par[0] != '0') + throw invalidParam("An integer is expected for parameter " + name); + return; + } + case LENGTH: { + if (par.empty() && !info->onoff) { + if (info->hint != "") + throw invalidParam(info->hint); + else + throw invalidParam("Please specify a latex length expression"); + } + if (!isValidLength(par)) + throw invalidParam("Invalid latex length expression for parameter " + name); + return; + } + case ONEOF: { + if (par.empty() && !info->onoff) { + if (info->hint != "") + throw invalidParam(info->hint); + else + throw invalidParam("Please specify one of " + string(info->info)); + } + // break value to allowed strings + vector lists; + string v; + for (size_t i = 0; info->info[i] != '\0'; ++i) { + if (info->info[i] == '\n') { + lists.push_back(v); + v = string(); + } else + v += info->info[i]; + } + if (!v.empty()) + lists.push_back(v); + + // good, find the string + if (std::find(lists.begin(), lists.end(), par) != lists.end()) + return; + // otherwise, produce a meaningful error message. + string matching_names; + for (vector::iterator it = lists.begin(); + it != lists.end(); ++it) { + if (it->size() >= par.size() && it->substr(0, par.size()) == par) { + if (matching_names.empty()) + matching_names += *it; + else + matching_names += ", " + *it; + } + } + if (matching_names.empty()) + throw invalidParam("Try one of " + string(info->info)); + else + throw invalidParam("I guess you mean " + matching_names); + return; + } + case SUBSETOF: { + if (par.empty() && !info->onoff) { + if (info->hint != "") + throw invalidParam(info->hint); + else + throw invalidParam("Please specify one or more of " + string(info->info)); + } + for (size_t i = 0; i < par.size(); ++i) + if (string(info->info).find(par[i], 0) == string::npos) + throw invalidParam("Parameter " + name + + " should be composed of one or more of " + info->info); + return; + } + } +} + + +InsetListingsParams::InsetListingsParams() : + inline_(false), status_(InsetCollapsable::Open), params_() +{ +} + + +InsetListingsParams::InsetListingsParams(string const & par, bool in, InsetCollapsable::CollapseStatus s) + : inline_(in), status_(s) +{ + // this will activate parameter validation. + fromEncodedString(par); +} + + +void InsetListingsParams::write(ostream & os) const +{ + if (inline_) + os << "true "; + else + os << "false "; + os << status_ << " \"" << encodedString() << "\""; +} + + +void InsetListingsParams::read(Lexer & lex) +{ + lex >> inline_; + int s; + lex >> s; + if (lex) + status_ = static_cast(s); + string par; + lex >> par; + fromEncodedString(par); +} + + +void InsetListingsParams::addParam(string const & key, string const & value) +{ + if (key.empty()) + return; + // exception may be thown. + parValidator(key.c_str()).validate(value); + if (!params_.empty()) + params_ += ','; + if (value.empty()) + params_ += key; + else { + // check onoff flag + size_t idx = 0; + while (listings_param_table[idx].name != key) + ++idx; + BOOST_ASSERT(listings_param_table[idx].name == key); + if (listings_param_table[idx].onoff && value == "false") + params_ += key; + else + params_ += key + '=' + value; + } +} + + +void InsetListingsParams::setParams(string const & par) +{ + string key; + string value; + bool isValue = false; + params_.clear(); + for (size_t i = 0; i < par.size(); ++i) { + // end of par + if (par[i] == '\n' || par[i] == ',') { + addParam(trim(key), trim(value)); + key = string(); + value = string(); + isValue = false; + } else if (par[i] == '=') + isValue = true; + else if (isValue) + value += par[i]; + else + key += par[i]; + } + if (!trim(key).empty()) + addParam(trim(key), trim(value)); +} + + +string InsetListingsParams::encodedString() const +{ + // Encode string! + // FIXME: + // '"' should be handled differently because it will + // terminate a lyx token. Right now, it is silently ignored. + string par; + for (size_t i = 0; i < params_.size(); ++i) { + BOOST_ASSERT(params_[i] != '\n'); + if (params_[i] != '"') + par += params_[i]; + } + return par; +} + + +string InsetListingsParams::separatedParams(bool keepComma) const +{ + // , might be used as regular parameter option so + // the prcess might be more complicated than what I am doing here + string opt; + for (size_t i = 0; i < params_.size(); ++i) + if (params_[i] == ',') { + if (keepComma) + opt += ",\n"; + else + opt += "\n"; + } else + opt += params_[i]; + return opt; +} + + +void InsetListingsParams::fromEncodedString(string const & in) +{ + // Decode string! + // Do nothing because " was silently ignored. + setParams(in); +} + + + +} // namespace lyx diff --git a/src/insets/InsetListingsParams.h b/src/insets/InsetListingsParams.h new file mode 100644 index 0000000000..3b111a11d1 --- /dev/null +++ b/src/insets/InsetListingsParams.h @@ -0,0 +1,100 @@ +// -*- C++ -*- +/** + * \file InsetListingsParams.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef INSETLISTINGSPARAMS_H +#define INSETLISTINGSPARAMS_H + +#include +#include +#include "Lexer.h" +#include "InsetCollapsable.h" + +namespace lyx { + +class InsetListingsParams { +public: + /// + InsetListingsParams(); + + /// + InsetListingsParams(std::string const &, bool in=false, + InsetCollapsable::CollapseStatus s = InsetCollapsable::Open); + + /// write parameters to an ostream + void write(std::ostream &) const; + + /// read parameters from an ostream + void read(Lexer &); + + /// valid parameter string + std::string params() const { return params_; } + + /// add key=value to params_ + void addParam(std::string const & key, std::string const & value); + + /// set params_ with par, throw an exception if par is valid + void setParams(std::string const & par); + + /// generate a parameter string that can be safely save and restored + /// by lyx' lexer + std::string encodedString() const; + + /// newline (\n) separated parameters. comma can be removed. + /// One possible complication is that , may appear in option value. + std::string separatedParams(bool keepComma = false) const; + + /// get parameter from encoded string + void fromEncodedString(std::string const & par); + + /// + bool isInline() const { return inline_; } + + /// + InsetCollapsable::CollapseStatus status() const { return status_; } + + /// + void setInline(bool i) { inline_ = i; } + + /// + void clear() { params_.clear(); } + +private: + /// inline or normal listings + bool inline_; + + /// listing parameters, this will always be a *valid* string + /// that can be passed to listing packages. + std::string params_; + + /// collapsable status + InsetCollapsable::CollapseStatus status_; +}; + + +class invalidParam : public std::exception { +public: + invalidParam(std::string const & details) : + details_(details) + {} + + virtual const char * what() const throw() { + return details_.c_str(); + } + + virtual ~invalidParam() throw() {} +private: + std::string const details_; +}; + + +} // namespace lyx + +#endif diff --git a/src/insets/Makefile.am b/src/insets/Makefile.am index 1cd44dab40..3fcb33d91e 100644 --- a/src/insets/Makefile.am +++ b/src/insets/Makefile.am @@ -77,6 +77,10 @@ libinsets_la_SOURCES = \ InsetLabel.h \ InsetLine.cpp \ InsetLine.h \ + InsetListings.h \ + InsetListings.cpp \ + InsetListingsParams.h \ + InsetListingsParams.cpp \ InsetMarginal.h \ InsetMarginal.cpp \ InsetNewline.cpp \ diff --git a/src/lfuns.h b/src/lfuns.h index acd0cb06fd..3415ae441b 100644 --- a/src/lfuns.h +++ b/src/lfuns.h @@ -380,6 +380,7 @@ enum kb_action { LFUN_CLEARPAGE_INSERT, // Ugras 20061125 LFUN_CLEARDOUBLEPAGE_INSERT, // Ugras 20061125 //290 + LFUN_LISTING_INSERT, // Herbert 20011110, bpeng 20070502 LFUN_LASTACTION // end of the table }; -- 2.39.5