]> git.lyx.org Git - lyx.git/blob - src/insets/insetgraphics.C
Herbert's unzip et al patch.
[lyx.git] / src / insets / insetgraphics.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995-2002 the LyX Team.
7  *           
8  * \author Baruch Even
9  * \author Herbert Voss <voss@lyx.org>
10  * ====================================================== */
11
12 /*
13 Known BUGS:
14     
15     * If the image is from the clipart, and the document is moved to another
16        directory, the user is screwed. Need a way to handle it.
17        This amounts to a problem of when to use relative or absolute file paths
18        We should probably use what the user asks to use... but when he chooses
19        by the file dialog we normally get an absolute path and this may not be 
20        what the user meant.
21        [Note that browseRelFile in helper_funcs.* provides a file name
22         which is relative if it is at reference path (here puffer path)
23         level or below, and an absolute path if the file name is not a
24         `natural' relative file name. In any case,
25             MakeAbsPath(filename, buf->filePath())
26         is guaranteed to provide the correct absolute path. This is what is
27         done know for include insets. Feel free to ask me -- JMarc
28         14/01/2002]
29         
30         * If we are trying to create a file in a read-only directory and there
31                 are graphics that need converting, the converting will fail because
32                 it is done in-place, into the same directory as the original image.
33                 This needs to be fixed in the src/converter.C file
34                 [ This is presumed to be fixed, needs testing.]
35
36         * We do not dither or resize the image in a WYSIWYM way, we load it at
37                 its original size and color, resizing is done in the final output,
38                 but not in the LyX window.
39
40 TODO Before initial production release:
41     * Replace insetfig everywhere
42         * Search for comments of the form
43             // INSET_GRAPHICS: remove this when InsetFig is thrown.
44           And act upon them. Make sure not to remove InsetFig code for the 
45                   1.2.0 release, only afterwards, after deployment shows InsetGraphics
46                   to be ok.
47         * What advanced features the users want to do?
48             Implement them in a non latex dependent way, but a logical way.
49             LyX should translate it to latex or any other fitting format.
50     * Add a way to roll the image file into the file format.
51     * When loading, if the image is not found in the expected place, try
52        to find it in the clipart, or in the same directory with the image.
53     * Keep a tab on the image file, if it changes, update the lyx view.
54         * The image choosing dialog could show thumbnails of the image formats
55           it knows of, thus selection based on the image instead of based on
56           filename.
57         * Add support for the 'picins' package.
58         * Add support for the 'picinpar' package.
59         * Improve support for 'subfigure' - Allow to set the various options
60                 that are possible.
61  */
62
63 /* NOTES:
64  * Fileformat:
65  * Current version is 1 (inset file format version), when changing it
66  * it should be changed in the Write() function when writing in one place
67  * and when reading one should change the version check and the error message.
68  * The filename is kept in  the lyx file in a relative way, so as to allow
69  * moving the document file and its images with no problem.
70  * 
71  *
72  * Conversions:
73  *   Postscript output means EPS figures.
74  *
75  *   PDF output is best done with PDF figures if it's a direct conversion
76  *   or PNG figures otherwise.
77  *      Image format
78  *      from        to
79  *      EPS         epstopdf
80  *      PS          ps2pdf
81  *      JPG/PNG     direct
82  *      PDF         direct
83  *      others      PNG
84  */
85
86 #include <config.h> 
87
88 #ifdef __GNUG__
89 #pragma implementation
90 #endif 
91
92 #include "insets/insetgraphics.h"
93 #include "insets/insetgraphicsParams.h"
94 #include "graphics/GraphicsCache.h"
95 #include "graphics/GraphicsCacheItem.h"
96
97 #include "frontends/Dialogs.h"
98 #include "LyXView.h"
99 #include "buffer.h"
100 #include "BufferView.h"
101 #include "converter.h"
102 #include "frontends/support/LyXImage.h"
103 #include "Painter.h"
104 #include "lyx_gui_misc.h"
105 #include "support/FileInfo.h"
106 #include "support/filetools.h"
107 #include "frontends/controllers/helper_funcs.h"
108 #include "support/lyxlib.h"
109 #include "lyxtext.h"
110 #include "lyxrc.h"
111 #include "font.h" // For the lyxfont class.
112 #include "fstream" // for ifstream in isEPS
113 #include <algorithm> // For the std::max
114 #include "support/lyxmanip.h"
115 #include "debug.h"
116 #include "gettext.h"
117
118 extern string system_tempdir;
119
120 using std::ifstream;
121 using std::ostream;
122 using std::endl;
123
124 ///////////////////////////////////////////////////////////////////////////
125 int const VersionNumber = 1;
126 ///////////////////////////////////////////////////////////////////////////
127
128 // This function is a utility function
129 // ... that should be with ChangeExtension ...
130 inline
131 string const RemoveExtension(string const & filename)
132 {
133         return ChangeExtension(filename, string());
134 }
135
136
137 // Initialize only those variables that do not have a constructor.
138 InsetGraphics::InsetGraphics()
139         : cacheHandle(0), imageLoaded(false)
140 {}
141
142
143 InsetGraphics::InsetGraphics(InsetGraphics const & ig, bool same_id)
144         : Inset(), SigC::Object()
145         , cacheHandle(ig.cacheHandle)
146         , imageLoaded(ig.imageLoaded)
147 {
148         setParams(ig.getParams());
149         if (same_id)
150                 id_ = ig.id_;
151 }
152
153
154 InsetGraphics::~InsetGraphics()
155 {
156         // Emits the hide signal to the dialog connected (if any)
157         hideDialog();
158 }
159
160
161 string const InsetGraphics::statusMessage() const
162 {
163         string msg;
164         if (cacheHandle.get()) {
165                 switch (cacheHandle->getImageStatus()) {
166                 case GraphicsCacheItem::UnknownError:
167                         msg = _("Unknown Error");
168                         break;
169                 case GraphicsCacheItem::Loading:
170                         msg = _("Loading...");
171                         break;
172                 case GraphicsCacheItem::ErrorReading:
173                         msg = _("Error reading");
174                         break;
175                 case GraphicsCacheItem::Converting:
176                         msg = _("Converting Image");
177                         break;
178                 case GraphicsCacheItem::ErrorConverting:
179                         msg = _("Error converting");
180                         break;
181                 case GraphicsCacheItem::Loaded:
182                         // No message to write.
183                         break;
184                 }
185         }
186         return msg;
187 }
188
189
190 int InsetGraphics::ascent(BufferView *, LyXFont const &) const
191 {
192         LyXImage * pixmap = 0;
193         if (cacheHandle.get() && (pixmap = cacheHandle->getImage()))
194                 return pixmap->getHeight();
195         else
196                 return 50;
197 }
198
199
200 int InsetGraphics::descent(BufferView *, LyXFont const &) const
201 {
202         // this is not true if viewport is used and clip is not.
203         return 0;
204 }
205
206
207 int InsetGraphics::width(BufferView *, LyXFont const & font) const
208 {
209         LyXImage * pixmap = 0;
210         
211         if (cacheHandle.get() && (pixmap = cacheHandle->getImage()))
212                 return pixmap->getWidth();
213         else {
214                 int font_width = 0;
215
216                 LyXFont msgFont(font);
217                 msgFont.setFamily(LyXFont::SANS_FAMILY);
218
219                 string const justname = OnlyFilename (params.filename);
220                 if (!justname.empty()) {
221                         msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
222                         font_width = lyxfont::width(justname, msgFont);
223                 }
224
225                 string const msg = statusMessage();
226                 if (!msg.empty()) {
227                         msgFont.setSize(LyXFont::SIZE_TINY);
228                         int const msg_width = lyxfont::width(msg, msgFont);
229                         font_width = std::max(font_width, msg_width);
230                 }
231                 
232                 return std::max(50, font_width + 15);
233         }
234 }
235
236
237 void InsetGraphics::draw(BufferView * bv, LyXFont const & font,
238                          int baseline, float & x, bool) const
239 {
240         Painter & paint = bv->painter();
241
242         int ldescent = descent(bv, font);
243         int lascent = ascent(bv, font);
244         int lwidth = width(bv, font);
245
246         // Make sure x is updated upon exit from this routine
247         int old_x = int(x);
248         x += lwidth;
249
250         // This will draw the graphics. If the graphics has not been loaded yet,
251         // we draw just a rectangle.
252         if (imageLoaded) {
253
254                 paint.image(old_x + 2, baseline - lascent,
255                             lwidth - 4, lascent + ldescent,
256                             cacheHandle->getImage());
257         } else {        
258                 // Get the image status, default to unknown error.
259                 GraphicsCacheItem::ImageStatus status = GraphicsCacheItem::UnknownError;
260                 if (lyxrc.use_gui && params.display != InsetGraphicsParams::NONE &&
261                     cacheHandle.get())
262                         status = cacheHandle->getImageStatus();
263                 // Check if the image is now ready.
264                 if (status == GraphicsCacheItem::Loaded) {
265                         imageLoaded = true;
266                         // Tell BufferView we need to be updated!
267                         bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
268                         return;
269                 }
270                 paint.rectangle(old_x + 2, baseline - lascent,
271                                 lwidth - 4,
272                                 lascent + ldescent);
273                 // Print the file name.
274                 LyXFont msgFont(font);
275                 msgFont.setFamily(LyXFont::SANS_FAMILY);
276                 string const justname = OnlyFilename (params.filename);
277                 if (!justname.empty()) {
278                         msgFont.setSize(LyXFont::SIZE_FOOTNOTE);
279                         paint.text(old_x + 8, 
280                                    baseline - lyxfont::maxAscent(msgFont) - 4,
281                                    justname, msgFont);
282                 }
283                 // Print the message.
284                 string const msg = statusMessage();
285                 if (!msg.empty()) {
286                         msgFont.setSize(LyXFont::SIZE_TINY);
287                         paint.text(old_x + 8, baseline - 4, msg, msgFont);
288                 }
289         }
290 }
291
292
293 void InsetGraphics::edit(BufferView *bv, int, int, unsigned int)
294 {
295         bv->owner()->getDialogs()->showGraphics(this);
296 }
297
298
299 void InsetGraphics::edit(BufferView * bv, bool)
300 {
301         edit(bv, 0, 0, 0);
302 }
303
304
305 Inset::EDITABLE InsetGraphics::editable() const
306 {
307         return IS_EDITABLE;
308 }
309
310
311 void InsetGraphics::write(Buffer const * buf, ostream & os) const
312 {
313         os << "Graphics FormatVersion " << VersionNumber << '\n';
314         params.Write(buf, os);
315 }
316
317
318 void InsetGraphics::read(Buffer const * buf, LyXLex & lex)
319 {
320         string const token = lex.getString();
321
322         if (token == "Graphics")
323                 readInsetGraphics(buf, lex);
324         else if (token == "Figure") // Compatibility reading of FigInset figures.
325                 readFigInset(buf, lex);
326         else
327                 lyxerr[Debug::INFO] << "Not a Graphics or Figure inset!\n";
328
329         updateInset();
330 }
331
332 void InsetGraphics::readInsetGraphics(Buffer const * buf, LyXLex & lex)
333 {
334         bool finished = false;
335
336         while (lex.isOK() && !finished) {
337                 lex.next();
338
339                 string const token = lex.getString();
340                 lyxerr[Debug::INFO] << "Token: '" << token << '\'' 
341                                     << std::endl;
342
343                 if (token.empty()) {
344                         continue;
345                 } else if (token == "\\end_inset") {
346                         finished = true;
347                 } else if (token == "FormatVersion") {
348                         lex.next();
349                         int version = lex.getInteger();
350                         if (version > VersionNumber)
351                                 lyxerr
352                                 << "This document was created with a newer Graphics widget"
353                                 ", You should use a newer version of LyX to read this"
354                                 " file."
355                                 << std::endl;
356                         // TODO: Possibly open up a dialog?
357                 }
358                 else {
359                         if (! params.Read(buf, lex, token))
360                                 lyxerr << "Unknown token, " << token << ", skipping." 
361                                         << std::endl;
362                 }
363         }
364 }
365
366 // FormatVersion < 1.0  (LyX < 1.2)
367 void InsetGraphics::readFigInset(Buffer const * buf, LyXLex & lex)
368 {
369         std::vector<string> const oldUnits =
370                 getVectorFromString("pt,cm,in,p%,c%");
371         bool finished = false;
372         // set the display default      
373         if (lyxrc.display_graphics == "mono") 
374             params.display = InsetGraphicsParams::MONOCHROME;
375         else if (lyxrc.display_graphics == "gray") 
376             params.display = InsetGraphicsParams::GRAYSCALE;
377         else if (lyxrc.display_graphics == "color") 
378             params.display = InsetGraphicsParams::COLOR;
379         else
380             params.display = InsetGraphicsParams::NONE;
381         while (lex.isOK() && !finished) {
382                 lex.next();
383
384                 string const token = lex.getString();
385                 lyxerr[Debug::INFO] << "Token: " << token << endl;
386                 
387                 if (token.empty())
388                         continue;
389                 else if (token == "\\end_inset") {
390                         finished = true;
391                 } else if (token == "file") {
392                         if (lex.next()) {
393                                 string const name = lex.getString();
394                                 string const path = buf->filePath();
395                                 params.filename = MakeAbsPath(name, path);
396                         }
397                 } else if (token == "extra") {
398                         if (lex.next());
399                         // kept for backwards compability. Delete in 0.13.x
400                 } else if (token == "subcaption") {
401                         if (lex.eatLine())
402                                 params.subcaptionText = lex.getString();
403                         params.subcaption = true;
404                 } else if (token == "label") {
405                         if (lex.next());
406                         // kept for backwards compability. Delete in 0.13.x
407                 } else if (token == "angle") {
408                         if (lex.next())
409                                 params.rotate = true;
410                                 params.rotateAngle = lex.getFloat();
411                 } else if (token == "size") {
412                         if (lex.next())
413                                 params.lyxwidth = LyXLength(lex.getString()+"pt");
414                         if (lex.next())
415                                 params.lyxheight = LyXLength(lex.getString()+"pt");
416                 } else if (token == "flags") {
417                         if (lex.next())
418                                 switch (lex.getInteger()) {
419                                 case 1: params.display = InsetGraphicsParams::MONOCHROME; 
420                                     break;
421                                 case 2: params.display = InsetGraphicsParams::GRAYSCALE; 
422                                     break;
423                                 case 3: params.display = InsetGraphicsParams::COLOR; 
424                                     break;
425                                 }
426                 } else if (token == "subfigure") {
427                         params.subcaption = true;
428                 } else if (token == "width") {
429                     if (lex.next()) {
430                         int i = lex.getInteger();
431                         if (lex.next()) {
432                             if (i == 5) {
433                                 params.scale = lex.getInteger();
434                                 params.size_type = InsetGraphicsParams::SCALE;
435                             } else {
436                                 params.width = LyXLength(lex.getString()+oldUnits[i]);
437                                 params.size_type = InsetGraphicsParams::WH;
438                             }
439                         }
440                     }
441                 } else if (token == "height") {
442                     if (lex.next()) {
443                         int i = lex.getInteger();
444                         if (lex.next()) {
445                             params.height = LyXLength(lex.getString()+oldUnits[i]);
446                             params.size_type = InsetGraphicsParams::WH;
447                         }
448                     }
449                 }
450         }
451 }
452
453 string const InsetGraphics::createLatexOptions() const
454 {
455         // Calculate the options part of the command, we must do it to a string
456         // stream since we might have a trailing comma that we would like to remove
457         // before writing it to the output stream.
458         ostringstream options;
459         if (!params.bb.empty())
460             options << "  bb=" << strip(params.bb) << ",\n";
461         if (params.draft)
462             options << "  draft,\n";
463         if (params.clip)
464             options << "  clip,\n";
465         if (params.size_type == InsetGraphicsParams::WH) {
466             if (!params.width.zero())
467                 options << "  width=" << params.width.asLatexString() << ",\n";
468             if (!params.height.zero())
469                 options << "  height=" << params.height.asLatexString() << ",\n";
470         } else if (params.size_type == InsetGraphicsParams::SCALE) {
471             if (params.scale > 0)
472                 options << "  scale=" << double(params.scale)/100.0 << ",\n";
473         }
474         if (params.keepAspectRatio)
475             options << "  keepaspectratio,\n";
476         // Make sure it's not very close to zero, a float can be effectively
477         // zero but not exactly zero.
478         if (!lyx::float_equal(params.rotateAngle, 0, 0.001) && params.rotate) {
479             options << "  angle=" << params.rotateAngle << ",\n";
480             if (!params.rotateOrigin.empty()) {
481                 options << "  origin=" << params.rotateOrigin[0];
482                 if (contains(params.rotateOrigin,"Top"))
483                     options << 't';
484                 else if (contains(params.rotateOrigin,"Bottom"))
485                     options << 'b';
486                 else if (contains(params.rotateOrigin,"Baseline"))
487                     options << 'B';
488                 options << ",\n";
489             }
490         }
491         if (!params.special.empty())
492             options << params.special << ",\n";
493         string opts = options.str().c_str();
494         return opts.substr(0,opts.size()-2);    // delete last ",\n"
495 }
496
497 namespace {
498 string decideOutputImageFormat(string const & suffix)
499 {
500         // lyxrc.pdf_mode means:
501         // Are we creating a PDF or a PS file?
502         // (Should actually mean, are we using latex or pdflatex).      
503         lyxerr << "decideOutput::lyxrc.pdf_mode = " << lyxrc.pdf_mode << "\n";
504         if (lyxrc.pdf_mode) {
505                 if (contains(suffix,"ps") || suffix == "pdf")
506                         return "pdf";
507                 else if (suffix == "jpg")
508                         return suffix;
509                 else
510                         return "png";
511         }
512         // If it's postscript, we always do eps.
513         lyxerr << "decideOutput: we have PostScript mode\n";
514         if (suffix != "ps")
515             return "eps";
516         else
517             return "ps";
518 }
519
520 } // Anon. namespace
521
522 string const InsetGraphics::prepareFile(Buffer const *buf) const
523 {
524         // do_convert = Do we need to convert the file?
525         // nice = Do we create a nice version?
526         //        This is used when exporting the latex file only.
527         // if (!do_convert)
528         //   return original filename
529         // if (!nice)
530         //   convert_place = temp directory
531         //   return new filename in temp directory
532         // else
533         //   convert_place = original file directory
534         //   return original filename without the extension
535         //
536         // first check if file is viewed in LyX. First local
537         // than global
538         if ((params.display == InsetGraphicsParams::NONE) || 
539             ((params.display == InsetGraphicsParams::DEFAULT) &&
540             (lyxrc.display_graphics == "no"))) {
541                 lyxerr << "InsetGraphics::no converting of: " << params.filename << "\n";
542                 return params.filename;
543         }
544         // if it's a zipped one, than let LaTeX do the rest!!!
545         if (zippedFile(params.filename)) {
546             lyxerr << "InsetGraphics::prepareFilter(zippedFile): return " 
547                     << params.filename << endl;
548             return params.filename;
549         }
550         // now we have unzipped files
551         // Get the extension (format) of the original file.
552         // we handle it like a virtual one, so we can have
553         // different extensions with the same type.
554         string const extension = getExtFromContents(params.filename);
555         // Are we creating a PDF or a PS file?
556         // (Should actually mean, are we usind latex or pdflatex).
557         string const image_target = decideOutputImageFormat(extension);
558         if (extension == image_target)
559                 return params.filename;
560         string outfile;
561         if (!buf->niceFile) {
562                 string const temp = AddName(buf->tmppath, params.filename);
563                 lyxerr << "temp = " << temp << "\n";
564                 outfile = RemoveExtension(temp);
565         } else {
566                 string const path = buf->filePath();
567                 string const relname = MakeRelPath(params.filename, path);
568                 outfile = RemoveExtension(relname);
569         }
570         lyxerr << "buf::tmppath = " << buf->tmppath << "\n";
571         lyxerr << "filename = " << params.filename << "\n";
572         lyxerr << "outfile = " << outfile << endl;
573         converters.convert(buf, params.filename, outfile, extension, image_target);
574         return outfile;
575 }
576
577
578 int InsetGraphics::latex(Buffer const *buf, ostream & os,
579                          bool /*fragile*/, bool/*fs*/) const
580 {
581         // If there is no file specified, just output a message about it in
582         // the latex output.
583         if (params.filename.empty()) {
584                 os  << "\\fbox{\\rule[-0.5in]{0pt}{1in}"
585                         << _("empty figure path") << "}\n";
586                 return 1; // One end of line marker added to the stream.
587         }
588         // Keep count of newlines that we issued.
589         int newlines = 0;
590         // This variables collect all the latex code that should be before and
591         // after the actual includegraphics command.
592         string before;
593         string after;
594         // Do we want subcaptions?
595         if (params.subcaption) {
596                 before += "\\subfigure[" + params.subcaptionText + "]{";
597                 after = '}' + after;
598         }
599         // We never use the starred form, we use the "clip" option instead.
600         os << before << "\\includegraphics";
601         // Write the options if there are any.
602         string const opts = createLatexOptions();
603         if (!opts.empty()) {
604                 os << "[%\n" << opts << ']';
605         }
606         // Make the filename relative to the lyx file
607         // and remove the extension so the LaTeX will use whatever is
608         // appropriate (when there are several versions in different formats)
609         string const filename = prepareFile(buf);
610         os << '{' << filename << '}' << after;
611         // Return how many newlines we issued.
612         return newlines;
613 }
614
615
616 int InsetGraphics::ascii(Buffer const *, ostream & os, int) const
617 {
618         // No graphics in ascii output. Possible to use gifscii to convert
619         // images to ascii approximation.
620         // 1. Convert file to ascii using gifscii
621         // 2. Read ascii output file and add it to the output stream.
622         // at least we send the filename
623         os << '<' << _("Graphicfile:") << params.filename << ">\n";
624         return 0;
625 }
626
627
628 int InsetGraphics::linuxdoc(Buffer const *, ostream &) const
629 {
630         // No graphics in LinuxDoc output. Should check how/what to add.
631         return 0;
632 }
633
634
635 // For explanation on inserting graphics into DocBook checkout:
636 // http://linuxdoc.org/LDP/LDP-Author-Guide/inserting-pictures.html
637 // See also the docbook guide at http://www.docbook.org/
638 int InsetGraphics::docbook(Buffer const * buf, ostream & os) const
639 {
640         // Change the path to be relative to the main file.
641         string const buffer_dir = buf->filePath();
642         string filename = RemoveExtension(
643                 MakeRelPath(params.filename, buffer_dir));
644
645         if (suffixIs(filename, ".eps"))
646                 filename.erase(filename.length() - 4);
647
648         // In DocBook v5.0, the graphic tag will be eliminated from DocBook, will 
649         // need to switch to MediaObject. However, for now this is sufficient and 
650         // easier to use.
651         os << "<graphic fileref=\"" << filename << "\"></graphic>";
652         return 0;
653 }
654
655
656 void InsetGraphics::validate(LaTeXFeatures & features) const
657 {
658         // If we have no image, we should not require anything.
659         if (params.filename.empty())
660                 return ;
661
662         features.require("graphicx");
663
664         if (params.subcaption)
665                 features.require("subfigure");
666 }
667
668
669 // Update the inset after parameters changed (read from file or changed in
670 // dialog.
671 void InsetGraphics::updateInset() const
672 {
673         GraphicsCache & gc = GraphicsCache::getInstance();
674         boost::shared_ptr<GraphicsCacheItem> temp(0);
675
676         // We do it this way so that in the face of some error, we will still
677         // be in a valid state.
678         InsetGraphicsParams::DisplayType local_display = params.display;
679         if (local_display == InsetGraphicsParams::DEFAULT) {
680                 if (lyxrc.display_graphics == "mono")
681                         local_display = InsetGraphicsParams::MONOCHROME;
682                 else if (lyxrc.display_graphics == "gray")
683                         local_display = InsetGraphicsParams::GRAYSCALE;
684                 else if (lyxrc.display_graphics == "color")
685                         local_display = InsetGraphicsParams::COLOR;
686                 else
687                         local_display = InsetGraphicsParams::NONE;
688         }
689
690         if (!params.filename.empty() && lyxrc.use_gui &&
691             local_display != InsetGraphicsParams::NONE) {
692                 temp = gc.addFile(params.filename);
693         }
694
695         // Mark the image as unloaded so that it gets updated.
696         imageLoaded = false;
697
698         cacheHandle = temp;
699 }
700
701
702 bool InsetGraphics::setParams(InsetGraphicsParams const & p)
703 {
704         // If nothing is changed, just return and say so.
705         if (params == p)
706                 return false;
707
708         // Copy the new parameters.
709         params = p;
710
711         // Update the inset with the new parameters.
712         updateInset();
713
714         // We have changed data, report it.
715         return true;
716 }
717
718
719 InsetGraphicsParams InsetGraphics::getParams() const
720 {
721         return params;
722 }
723
724
725 Inset * InsetGraphics::clone(Buffer const &, bool same_id) const
726 {
727         return new InsetGraphics(*this, same_id);
728 }
729