]> git.lyx.org Git - lyx.git/blobdiff - src/insets/insetgraphics.C
Don't remove cell selections after fontchange.
[lyx.git] / src / insets / insetgraphics.C
index 5c2a21d56198b2f525b1af0e1e3aab9ce51366f1..1dc04a8530c0eea9948d5443e3762bdede8630ab 100644 (file)
@@ -37,10 +37,6 @@ Known BUGS:
                its original size and color, resizing is done in the final output,
                but not in the LyX window.
 
-       * EPS figures are not fully detected, they may have a lot of possible
-               suffixes so we need to read the file and detect if it's EPS or not.
-               [Implemented, need testing]
-               
 TODO Before initial production release:
     * Replace insetfig everywhere
         * Search for comments of the form
@@ -81,6 +77,7 @@ TODO Before initial production release:
  *     Image format
  *     from        to
  *     EPS         epstopdf
+ *     PS          ps2pdf
  *     JPG/PNG     direct
  *     PDF         direct
  *     others      PNG
@@ -94,38 +91,47 @@ TODO Before initial production release:
 
 #include "insets/insetgraphics.h"
 #include "insets/insetgraphicsParams.h"
+
 #include "graphics/GraphicsCache.h"
 #include "graphics/GraphicsCacheItem.h"
 
-#include "frontends/Dialogs.h"
 #include "LyXView.h"
 #include "buffer.h"
 #include "BufferView.h"
 #include "converter.h"
-#include "frontends/support/LyXImage.h"
 #include "Painter.h"
 #include "lyx_gui_misc.h"
-#include "support/FileInfo.h"
-#include "support/filetools.h"
-#include "frontends/controllers/helper_funcs.h"
-#include "support/lyxlib.h"
 #include "lyxtext.h"
 #include "lyxrc.h"
-#include "font.h" // For the lyxfont class.
-#include "fstream" // for ifstream in isEPS
-#include <algorithm> // For the std::max
-#include "support/lyxmanip.h"
+#include "font.h"
 #include "debug.h"
 #include "gettext.h"
 
+#include "frontends/Dialogs.h"
+#include "frontends/Alert.h"
+#include "frontends/controllers/helper_funcs.h"
+#include "frontends/support/LyXImage.h"
+
+#include "support/FileInfo.h"
+#include "support/filetools.h"
+#include "support/lyxlib.h"
+#include "support/lyxmanip.h"
+#include "support/lyxalgo.h"
+
+#include <fstream>
+#include <algorithm>
+
 extern string system_tempdir;
 
 using std::ifstream;
 using std::ostream;
 using std::endl;
+using std::max;
+using std::vector;
+
 
 ///////////////////////////////////////////////////////////////////////////
-int VersionNumber = 1;
+int const VersionNumber = 1;
 ///////////////////////////////////////////////////////////////////////////
 
 // This function is a utility function
@@ -137,9 +143,25 @@ string const RemoveExtension(string const & filename)
 }
 
 
+namespace {
+
+string const unique_id()
+{
+       static unsigned int seed = 1000;
+
+       ostringstream ost;
+       ost << "graph" << ++seed;
+
+       // Needed if we use lyxstring.
+       return ost.str().c_str();
+}
+
+} // namespace anon
+
+
 // Initialize only those variables that do not have a constructor.
 InsetGraphics::InsetGraphics()
-       : cacheHandle(0), imageLoaded(false)
+       : cacheHandle(0), imageLoaded(false), graphic_label(unique_id())
 {}
 
 
@@ -147,6 +169,7 @@ InsetGraphics::InsetGraphics(InsetGraphics const & ig, bool same_id)
        : Inset(), SigC::Object()
        , cacheHandle(ig.cacheHandle)
        , imageLoaded(ig.imageLoaded)
+       , graphic_label(unique_id())
 {
        setParams(ig.getParams());
        if (same_id)
@@ -161,8 +184,7 @@ InsetGraphics::~InsetGraphics()
 }
 
 
-string const
-InsetGraphics::statusMessage() const
+string const InsetGraphics::statusMessage() const
 {
        string msg;
        if (cacheHandle.get()) {
@@ -230,10 +252,10 @@ int InsetGraphics::width(BufferView *, LyXFont const & font) const
                if (!msg.empty()) {
                        msgFont.setSize(LyXFont::SIZE_TINY);
                        int const msg_width = lyxfont::width(msg, msgFont);
-                       font_width = std::max(font_width, msg_width);
+                       font_width = max(font_width, msg_width);
                }
                
-               return std::max(50, font_width + 15);
+               return max(50, font_width + 15);
        }
 }
 
@@ -258,32 +280,25 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
                paint.image(old_x + 2, baseline - lascent,
                            lwidth - 4, lascent + ldescent,
                            cacheHandle->getImage());
-       } else {
-               
+       } else {        
                // Get the image status, default to unknown error.
                GraphicsCacheItem::ImageStatus status = GraphicsCacheItem::UnknownError;
-               if (lyxrc.display_graphics != "no" && lyxrc.use_gui
-                   && params.display != InsetGraphicsParams::NONE &&
+               if (lyxrc.use_gui && params.display != InsetGraphicsParams::NONE &&
                    cacheHandle.get())
                        status = cacheHandle->getImageStatus();
-               
                // Check if the image is now ready.
                if (status == GraphicsCacheItem::Loaded) {
                        imageLoaded = true;
-
                        // Tell BufferView we need to be updated!
                        bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
                        return;
                }
-
                paint.rectangle(old_x + 2, baseline - lascent,
                                lwidth - 4,
                                lascent + ldescent);
-
                // Print the file name.
                LyXFont msgFont(font);
                msgFont.setFamily(LyXFont::SANS_FAMILY);
-
                string const justname = OnlyFilename (params.filename);
                if (!justname.empty()) {
                        msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
@@ -291,7 +306,6 @@ void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
                                   baseline - lyxfont::maxAscent(msgFont) - 4,
                                   justname, msgFont);
                }
-
                // Print the message.
                string const msg = statusMessage();
                if (!msg.empty()) {
@@ -350,7 +364,7 @@ void InsetGraphics::readInsetGraphics(Buffer const * buf, LyXLex & lex)
 
                string const token = lex.getString();
                lyxerr[Debug::INFO] << "Token: '" << token << '\'' 
-                                   << std::endl;
+                                   << endl;
 
                if (token.empty()) {
                        continue;
@@ -364,24 +378,32 @@ void InsetGraphics::readInsetGraphics(Buffer const * buf, LyXLex & lex)
                                << "This document was created with a newer Graphics widget"
                                ", You should use a newer version of LyX to read this"
                                " file."
-                               << std::endl;
+                               << endl;
                        // TODO: Possibly open up a dialog?
                }
                else {
                        if (! params.Read(buf, lex, token))
                                lyxerr << "Unknown token, " << token << ", skipping." 
-                                       << std::endl;
+                                       << endl;
                }
        }
 }
 
-
+// FormatVersion < 1.0  (LyX < 1.2)
 void InsetGraphics::readFigInset(Buffer const * buf, LyXLex & lex)
 {
-       std::vector<string> const oldUnits =
+       vector<string> const oldUnits =
                getVectorFromString("pt,cm,in,p%,c%");
        bool finished = false;
-       
+       // set the display default      
+       if (lyxrc.display_graphics == "mono") 
+           params.display = InsetGraphicsParams::MONOCHROME;
+       else if (lyxrc.display_graphics == "gray") 
+           params.display = InsetGraphicsParams::GRAYSCALE;
+       else if (lyxrc.display_graphics == "color") 
+           params.display = InsetGraphicsParams::COLOR;
+       else
+           params.display = InsetGraphicsParams::NONE;
        while (lex.isOK() && !finished) {
                lex.next();
 
@@ -410,6 +432,7 @@ void InsetGraphics::readFigInset(Buffer const * buf, LyXLex & lex)
                        // kept for backwards compability. Delete in 0.13.x
                } else if (token == "angle") {
                        if (lex.next())
+                               params.rotate = true;
                                params.rotateAngle = lex.getFloat();
                } else if (token == "size") {
                        if (lex.next())
@@ -417,13 +440,15 @@ void InsetGraphics::readFigInset(Buffer const * buf, LyXLex & lex)
                        if (lex.next())
                                params.lyxheight = LyXLength(lex.getString()+"pt");
                } else if (token == "flags") {
-                       InsetGraphicsParams::DisplayType tmp = InsetGraphicsParams::COLOR;
                        if (lex.next())
                                switch (lex.getInteger()) {
-                               case 1: tmp = InsetGraphicsParams::MONOCHROME; break;
-                               case 2: tmp = InsetGraphicsParams::GRAYSCALE; break;
+                               case 1: params.display = InsetGraphicsParams::MONOCHROME; 
+                                   break;
+                               case 2: params.display = InsetGraphicsParams::GRAYSCALE; 
+                                   break;
+                               case 3: params.display = InsetGraphicsParams::COLOR; 
+                                   break;
                                }
-                       params.display = tmp;
                } else if (token == "subfigure") {
                        params.subcaption = true;
                } else if (token == "width") {
@@ -458,124 +483,64 @@ string const InsetGraphics::createLatexOptions() const
        // before writing it to the output stream.
        ostringstream options;
        if (!params.bb.empty())
-           options << "bb=" << strip(params.bb) << ',';
+           options << "  bb=" << strip(params.bb) << ",\n";
        if (params.draft)
-           options << "%\n  draft,";
+           options << "  draft,\n";
        if (params.clip)
-           options << "%\n  clip,";
+           options << "  clip,\n";
        if (params.size_type == InsetGraphicsParams::WH) {
            if (!params.width.zero())
-               options << "%\n  width=" << params.width.asLatexString() << ',';
+               options << "  width=" << params.width.asLatexString() << ",\n";
            if (!params.height.zero())
-               options << "%\n  height=" << params.height.asLatexString() << ',';
+               options << "  height=" << params.height.asLatexString() << ",\n";
        } else if (params.size_type == InsetGraphicsParams::SCALE) {
            if (params.scale > 0)
-               options << "%\n  scale=" << double(params.scale)/100.0 << ',';
+               options << "  scale=" << double(params.scale)/100.0 << ",\n";
        }
        if (params.keepAspectRatio)
-           options << "%\n  keepaspectratio,";
+           options << "  keepaspectratio,\n";
        // Make sure it's not very close to zero, a float can be effectively
        // zero but not exactly zero.
-       if (!lyx::float_equal(params.rotateAngle, 0, 0.001)) {
-           options << "%\n  angle=" << params.rotateAngle << ',';
+       if (!lyx::float_equal(params.rotateAngle, 0, 0.001) && params.rotate) {
+           options << "  angle=" << params.rotateAngle << ",\n";
            if (!params.rotateOrigin.empty()) {
-               options << "%\n  origin=";
-               options << params.rotateOrigin[0];
+               options << "  origin=" << params.rotateOrigin[0];
                if (contains(params.rotateOrigin,"Top"))
                    options << 't';
                else if (contains(params.rotateOrigin,"Bottom"))
                    options << 'b';
                else if (contains(params.rotateOrigin,"Baseline"))
                    options << 'B';
-               options << ',';
+               options << ",\n";
            }
        }
        if (!params.special.empty())
-           options << params.special << ',';
+           options << params.special << ",\n";
        string opts = options.str().c_str();
-       opts = strip(opts, ',');
-       return opts;
+       return opts.substr(0,opts.size()-2);    // delete last ",\n"
 }
 
 namespace {
-
-enum FileType {
-       EPS,
-       PNG,
-       JPEG,
-       GIF,
-       PDF,
-       UNKNOWN
-};
-
-bool isEPS(string const & filename)
-{
-       if (filename.empty() || !IsFileReadable(filename)) return false;
-
-       ifstream ifs(filename.c_str());
-
-       if (!ifs) return false; // Couldn't open file...
-
-       bool is_eps = false; // Have we recognized the file as EPS?
-       string to_find = "%!PS-Adobe-"; // The string we use to recognize
-       int const max_attempts = 500; // Maximum strings to read to attempt recognition
-       int count = 0; // Counter of attempts.
-       string str;
-       for (; count < max_attempts; ++count) {
-               if (ifs.eof()) {
-                       lyxerr[Debug::INFO] << "InsetGraphics (isEPS)"
-                               " End of file reached and it wasn't found to be EPS!" << endl;
-                       break;
-               }
-
-               ifs >> str;
-               if (str.find(to_find)) {
-                       is_eps = true;
-                       break;
-               }
-       }
-
-       return is_eps;
-}
-
-enum FileType classifyFileType(string const & filename, string const & suffix)
-{
-       if (suffix == "png")
-               return PNG;
-       else if (suffix == "jpg" || suffix == "jpeg")
-               return JPEG;
-       else if (suffix == "gif")
-               return GIF;
-       else if (suffix == "pdf")
-               return PDF;
-       else if (isEPS(filename))
-               return EPS;
-
-       return UNKNOWN;
-}
-
-string decideOutputImageFormat(string const & suffix, enum FileType type)
+string decideOutputImageFormat(string const & suffix)
 {
        // lyxrc.pdf_mode means:
        // Are we creating a PDF or a PS file?
        // (Should actually mean, are we using latex or pdflatex).      
+       lyxerr[Debug::INFO] << "decideOutput::lyxrc.pdf_mode = " << lyxrc.pdf_mode << "\n";
        if (lyxrc.pdf_mode) {
-               if (type == EPS || type == EPS || type == PDF)
+               if (contains(suffix,"ps") || suffix == "pdf")
                        return "pdf";
-               else if (type == JPEG)
+               else if (suffix == "jpg")
                        return suffix;
                else
                        return "png";
        }
-
        // If it's postscript, we always do eps.
-       // There are many suffixes that are actually EPS (ask Garst for example)
-       // so we detect if it's an EPS by looking in the file, if it is, we return
-       // the same suffix of the file so it won't be converted.
-       if (type == EPS)
-               return suffix;
-       
-       return "eps";
+       lyxerr[Debug::INFO] << "decideOutput: we have PostScript mode\n";
+       if (suffix != "ps")
+           return "eps";
+       else
+           return "ps";
 }
 
 } // Anon. namespace
@@ -585,10 +550,8 @@ string const InsetGraphics::prepareFile(Buffer const *buf) const
        // do_convert = Do we need to convert the file?
        // nice = Do we create a nice version?
        //        This is used when exporting the latex file only.
-       // 
        // if (!do_convert)
        //   return original filename
-       // 
        // if (!nice)
        //   convert_place = temp directory
        //   return new filename in temp directory
@@ -596,33 +559,38 @@ string const InsetGraphics::prepareFile(Buffer const *buf) const
        //   convert_place = original file directory
        //   return original filename without the extension
        //
-       
+       // if it's a zipped one, than let LaTeX do the rest!!!
+       if ((zippedFile(params.filename) && params.noUnzip) || buf->niceFile) {
+           lyxerr[Debug::INFO] << "don't unzip file or export latex" 
+                   << params.filename << endl;
+           return params.filename;
+       }
+       string filename_ = params.filename;
+       if (zippedFile(filename_))
+           filename_ = unzipFile(filename_);
+       // now we have unzipped files
        // Get the extension (format) of the original file.
-       string const extension = GetExtension(params.filename);
-       FileType type = classifyFileType(params.filename, extension);
-       
-       // Are we creating a PDF or a PS file?
-       // (Should actually mean, are we usind latex or pdflatex).
-       string const image_target = decideOutputImageFormat(extension, type);
-
-       if (extension == image_target)
-               return params.filename;
-
+       // we handle it like a virtual one, so we can have
+       // different extensions with the same type.
+       string const extension = getExtFromContents(filename_);
+       // are we usind latex ((e)ps) or pdflatex (pdf,jpg,png)
+       string const image_target = decideOutputImageFormat(extension);
+       if (extension == image_target)          // :-)
+               return filename_;
+//     commented out to check if the "not exist"bug is fixed.
+//     if (!IsFileReadable(filename_)) {       // :-(
+//             Alert::alert(_("File") + params.filename,
+//                        _("isn't readable or doesn't exists!"));
+//             return filename_;
+//     }
        string outfile;
-       if (!buf->niceFile) {
-               string const temp = AddName(buf->tmppath, params.filename);
-               outfile = RemoveExtension(temp);
-               
-               //lyxerr << "buf::tmppath = " << buf->tmppath << "\n";
-               //lyxerr << "filename = " << params.filename << "\n";
-               //lyxerr << "temp = " << temp << "\n";
-               //lyxerr << "outfile = " << outfile << endl;
-       } else {
-               string const path = buf->filePath();
-               string const relname = MakeRelPath(params.filename, path);
-               outfile = RemoveExtension(relname);
-       }
-       converters.convert(buf, params.filename, outfile, extension, image_target);
+       string const temp = AddName(buf->tmppath, filename_);
+       outfile = RemoveExtension(temp);
+       lyxerr[Debug::INFO] << "tempname = " << temp << "\n";
+       lyxerr[Debug::INFO] << "buf::tmppath = " << buf->tmppath << "\n";
+       lyxerr[Debug::INFO] << "filename_ = " << filename_ << "\n";
+       lyxerr[Debug::INFO] << "outfile = " << outfile << endl;
+       converters.convert(buf, filename_, outfile, extension, image_target);
        return outfile;
 }
 
@@ -637,42 +605,44 @@ int InsetGraphics::latex(Buffer const *buf, ostream & os,
                        << _("empty figure path") << "}\n";
                return 1; // One end of line marker added to the stream.
        }
-       // Keep count of newlines that we issued.
-       int newlines = 0;
-       // This variables collect all the latex code that should be before and
+       // These variables collect all the latex code that should be before and
        // after the actual includegraphics command.
        string before;
        string after;
        // Do we want subcaptions?
        if (params.subcaption) {
                before += "\\subfigure[" + params.subcaptionText + "]{";
-               after = '}' + after;
+               after = '}';
        }
        // We never use the starred form, we use the "clip" option instead.
-       os << before << "\\includegraphics";
+       before += "\\includegraphics";
        // Write the options if there are any.
        string const opts = createLatexOptions();
        if (!opts.empty()) {
-               os << "[%\n  " << opts << ']';
+               before += ("[%\n" + opts +']');
        }
        // Make the filename relative to the lyx file
        // and remove the extension so the LaTeX will use whatever is
        // appropriate (when there are several versions in different formats)
-       string const filename = prepareFile(buf);
-       os << '{' << filename << '}' << after;
+       string const latex_str = before + '{' + prepareFile(buf) + '}' + after;
+       os << latex_str;
        // Return how many newlines we issued.
+       int const newlines =
+               int(lyx::count(latex_str.begin(), latex_str.end(),'\n') + 1);
+       // lyxerr << "includegraphics: " << newlines << " lines of text"
+       //        << endl; 
        return newlines;
 }
 
 
-int InsetGraphics::ascii(Buffer const *, ostream &, int) const
+int InsetGraphics::ascii(Buffer const *, ostream & os, int) const
 {
        // No graphics in ascii output. Possible to use gifscii to convert
        // images to ascii approximation.
-       
        // 1. Convert file to ascii using gifscii
        // 2. Read ascii output file and add it to the output stream.
-       
+       // at least we send the filename
+       os << '<' << _("Graphicfile:") << params.filename << ">\n";
        return 0;
 }
 
@@ -687,20 +657,12 @@ int InsetGraphics::linuxdoc(Buffer const *, ostream &) const
 // For explanation on inserting graphics into DocBook checkout:
 // http://linuxdoc.org/LDP/LDP-Author-Guide/inserting-pictures.html
 // See also the docbook guide at http://www.docbook.org/
-int InsetGraphics::docbook(Buffer const * buf, ostream & os) const
+int InsetGraphics::docbook(Buffer const *, ostream & os) const
 {
-       // Change the path to be relative to the main file.
-       string const buffer_dir = buf->filePath();
-       string filename = RemoveExtension(
-               MakeRelPath(params.filename, buffer_dir));
-
-       if (suffixIs(filename, ".eps"))
-               filename.erase(filename.length() - 4);
-
        // In DocBook v5.0, the graphic tag will be eliminated from DocBook, will 
        // need to switch to MediaObject. However, for now this is sufficient and 
        // easier to use.
-       os << "<graphic fileref=\"" << filename << "\"></graphic>";
+       os << "<graphic fileref=\"&" << graphic_label << ";\">";
        return 0;
 }
 
@@ -711,6 +673,8 @@ void InsetGraphics::validate(LaTeXFeatures & features) const
        if (params.filename.empty())
                return ;
 
+       features.includeFile(graphic_label, RemoveExtension(params.filename));
+
        features.require("graphicx");
 
        if (params.subcaption)
@@ -727,9 +691,20 @@ void InsetGraphics::updateInset() const
 
        // We do it this way so that in the face of some error, we will still
        // be in a valid state.
-       if (!params.filename.empty() && lyxrc.use_gui
-           && lyxrc.display_graphics != "no" 
-           && params.display != InsetGraphicsParams::NONE) {
+       InsetGraphicsParams::DisplayType local_display = params.display;
+       if (local_display == InsetGraphicsParams::DEFAULT) {
+               if (lyxrc.display_graphics == "mono")
+                       local_display = InsetGraphicsParams::MONOCHROME;
+               else if (lyxrc.display_graphics == "gray")
+                       local_display = InsetGraphicsParams::GRAYSCALE;
+               else if (lyxrc.display_graphics == "color")
+                       local_display = InsetGraphicsParams::COLOR;
+               else
+                       local_display = InsetGraphicsParams::NONE;
+       }
+
+       if (!params.filename.empty() && lyxrc.use_gui &&
+           local_display != InsetGraphicsParams::NONE) {
                temp = gc.addFile(params.filename);
        }