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