]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetListings.cpp
* Inset:
[lyx.git] / src / insets / InsetListings.cpp
index 59b289a8ffbe0167889bd053b4cddb1651b71dc0..0c6b472da86d171f4f73db9d0686dc52fcaa8fb2 100644 (file)
@@ -4,6 +4,7 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Bo Peng
+ * \author Jürgen Spitzmüller
  *
  * Full author contact details are available in file CREDITS.
  */
 #include <config.h>
 
 #include "InsetListings.h"
+#include "InsetCaption.h"
 
+#include "Buffer.h"
+#include "BufferParams.h"
+#include "Counters.h"
 #include "Language.h"
 #include "gettext.h"
 #include "DispatchResult.h"
 #include "FuncRequest.h"
 #include "FuncStatus.h"
+#include "MetricsInfo.h"
 #include "Cursor.h"
 #include "support/lstrings.h"
 
 namespace lyx {
 
 using support::token;
+using support::contains;
+using support::subst;
 
-using std::auto_ptr;
 using std::istringstream;
 using std::ostream;
 using std::ostringstream;
 using std::string;
 
+char const lstinline_delimiters[] =
+       "!*()-=+|;:'\"`,<.>/?QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
 
 void InsetListings::init()
 {
-       // FIXME: define Color::listing?
+       setButtonLabel();
        Font font(Font::ALL_SANE);
        font.decSize();
        font.decSize();
-       font.setColor(Color::foreground);
+       font.setColor(Color::none);
        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);
+       // FIXME: what to do with those?
+       //text_.current_font.setLanguage(latex_language);
+       //text_.real_current_font.setLanguage(latex_language);
 }
 
 
@@ -58,15 +64,15 @@ InsetListings::InsetListings(BufferParams const & bp, InsetListingsParams const
 
 
 InsetListings::InsetListings(InsetListings const & in)
-       : InsetERT(in)
+       : InsetERT(in), params_(in.params_)
 {
        init();
 }
 
 
-auto_ptr<Inset> InsetListings::doClone() const
+Inset * InsetListings::clone() const
 {
-       return auto_ptr<Inset>(new InsetListings(*this));
+       return new InsetListings(*this);
 }
 
 
@@ -76,9 +82,24 @@ InsetListings::~InsetListings()
 }
 
 
-bool InsetListings::display() const
+Inset::DisplayType InsetListings::display() const
 {
-       return !params().isInline();
+       return params().isInline() || params().isFloat() ? Inline : AlignLeft;
+}
+
+
+void InsetListings::updateLabels(Buffer const & buf, ParIterator const & it)
+{
+       Counters & cnts = buf.params().getTextClass().counters();
+       string const saveflt = cnts.current_float();
+
+       // Tell to captions what the current float is
+       cnts.current_float("listing");
+
+       InsetCollapsable::updateLabels(buf, it);
+
+       //reset afterwards
+       cnts.current_float(saveflt);
 }
 
 
@@ -116,59 +137,82 @@ void InsetListings::read(Buffer const & buf, Lexer & lex)
                        break;
                }
        }
-       InsetCollapsable::read(buf, lex);
+       InsetERT::read(buf, lex);
 }
 
 
 docstring const InsetListings::editMessage() const
 {
-       return _("Opened Listings Inset");
+       return _("Opened Listing Inset");
 }
 
 
-int InsetListings::latex(Buffer const &, odocstream & os,
-                   OutputParams const &) const
+int InsetListings::latex(Buffer const & buf, odocstream & os,
+                   OutputParams const & runparams) const
 {
-       string param_string = params().encodedString();
+       string param_string = params().params();
        // 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;
-       }
+       bool isInline = params().isInline();
+       // get the paragraphs. We can not output them directly to given odocstream
+       // because we can not yet determine the delimiter character of \lstinline
+       docstring code;
        ParagraphList::const_iterator par = paragraphs().begin();
        ParagraphList::const_iterator end = paragraphs().end();
 
        while (par != end) {
                pos_type siz = par->size();
+               bool captionline = false;
                for (pos_type i = 0; i < siz; ++i) {
-                       // ignore all struck out text
-                       if (par->isDeleted(i))
+                       if (i == 0 && par->isInset(i) && i + 1 == siz)
+                               captionline = true;
+                       // ignore all struck out text and (caption) insets
+                       if (par->isDeleted(i) || par->isInset(i))
                                continue;
-                       os.put(par->getChar(i));
+                       code += 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";
+               // they are simply joined. Otherwise, expect latex errors.
+               if (par != end && !isInline && !captionline) {
+                       code += "\n";
                        ++lines;
                }
        }
-       if (lstinline)
-               os << "}";              
-       else {
-               os << "\n\\end{lstlisting}\n\\endgroup\n";
+       if (isInline) {
+                char const * delimiter = lstinline_delimiters;
+               for (; delimiter != '\0'; ++delimiter)
+                       if (!contains(code, *delimiter))
+                               break;
+               // This code piece contains all possible special character? !!!
+               // Replace ! with a warning message and use ! as delimiter.
+               if (*delimiter == '\0') {
+                       code = subst(code, from_ascii("!"), from_ascii(" WARNING: no lstline delimiter can be used "));
+                       delimiter = lstinline_delimiters;
+               }
+               if (param_string.empty())
+                       os << "\\lstinline" << *delimiter;
+               else
+                       os << "\\lstinline[" << from_ascii(param_string) << "]" << *delimiter;
+                os << code
+                   << *delimiter;
+       } else {
+               docstring const caption = getCaption(buf, runparams);
+               if (param_string.empty() && caption.empty())
+                       os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}\n";
+               else {
+                       os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}[";
+                       if (!caption.empty()) {
+                               os << "caption={" << caption << '}';
+                               if (!param_string.empty())
+                                       os << ',';
+                       }
+                       os << from_utf8(param_string) << "]\n";
+               }
+               lines += 4;
+                os << code
+                   << "\n\\end{lstlisting}\n\\endgroup\n";
                lines += 3;
        }
 
@@ -186,7 +230,7 @@ void InsetListings::doDispatch(Cursor & cur, FuncRequest & cmd)
        }
        case LFUN_INSET_DIALOG_UPDATE:
                InsetListingsMailer(*this).updateDialog(&cur.bv());
-               break;  
+               break;
        case LFUN_MOUSE_RELEASE: {
                if (cmd.button() == mouse_button::button3 && hitButton(cmd)) {
                        InsetListingsMailer(*this).showDialog(&cur.bv());
@@ -209,6 +253,9 @@ bool InsetListings::getStatus(Cursor & cur, FuncRequest const & cmd,
                case LFUN_INSET_DIALOG_UPDATE:
                        status.enabled(true);
                        return true;
+               case LFUN_CAPTION_INSERT:
+                       status.enabled(!params().isInline());
+                       return true;
                default:
                        return InsetERT::getStatus(cur, cmd, status);
        }
@@ -218,7 +265,27 @@ bool InsetListings::getStatus(Cursor & cur, FuncRequest const & cmd,
 void InsetListings::setButtonLabel()
 {
        // FIXME UNICODE
-       setLabel(isOpen() ?  _("Listings") : getNewLabel(_("Listings")));
+       setLabel(isOpen() ?  _("Listing") : getNewLabel(_("Listing")));
+}
+
+
+void InsetListings::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+       Font tmpfont = mi.base.font;
+       getDrawFont(mi.base.font);
+       mi.base.font.realize(tmpfont);
+       InsetCollapsable::metrics(mi, dim);
+       mi.base.font = tmpfont;
+}
+
+
+void InsetListings::draw(PainterInfo & pi, int x, int y) const
+{
+       Font tmpfont = pi.base.font;
+       getDrawFont(pi.base.font);
+       pi.base.font.realize(tmpfont);
+       InsetCollapsable::draw(pi, x, y);
+       pi.base.font = tmpfont;
 }
 
 
@@ -238,12 +305,38 @@ bool InsetListings::showInsetDialog(BufferView * bv) const
 
 void InsetListings::getDrawFont(Font & font) const
 {
-       font = Font(Font::ALL_INHERIT, english_language);
+       font = Font(Font::ALL_INHERIT, latex_language);
        font.setFamily(Font::TYPEWRITER_FAMILY);
+       // FIXME: define Color::listing?
        font.setColor(Color::foreground);
 }
 
 
+docstring InsetListings::getCaption(Buffer const & buf,
+                   OutputParams const & runparams) const
+{
+       if (paragraphs().empty())
+               return docstring();
+
+       ParagraphList::const_iterator pit = paragraphs().begin();
+       for (; pit != paragraphs().end(); ++pit) {
+               InsetList::const_iterator it = pit->insetlist.begin();
+               for (; it != pit->insetlist.end(); ++it) {
+                       Inset & inset = *it->inset;
+                       if (inset.lyxCode() == Inset::CAPTION_CODE) {
+                               odocstringstream ods;
+                               InsetCaption * ins =
+                                       static_cast<InsetCaption *>(it->inset);
+                               ins->getOptArg(buf, ods, runparams);
+                               ins->getArgument(buf, ods, runparams);
+                               return ods.str();
+                       }
+               }
+       }
+       return docstring();
+}
+
+
 string const InsetListingsMailer::name_("listings");
 
 InsetListingsMailer::InsetListingsMailer(InsetListings & inset)