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