]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiGraphics.cpp
s/isFileReadable/isReadableFile;
[lyx.git] / src / frontends / qt4 / GuiGraphics.cpp
1 /**
2  * \file GuiGraphics.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author John Levon
8  * \author Edwin Leuven
9  * \author Herbert Voß
10  * \author Richard Heck
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "GuiGraphics.h"
18
19 #include "debug.h"
20 #include "LengthCombo.h"
21 #include "Length.h"
22 #include "LyXRC.h"
23 #include "qt_helpers.h"
24 #include "Validator.h"
25
26 #include "FuncRequest.h"
27 #include "gettext.h"
28
29 #include "graphics/GraphicsCache.h"
30 #include "graphics/GraphicsCacheItem.h"
31 #include "graphics/GraphicsImage.h"
32
33 #include "insets/InsetGraphicsParams.h"
34
35 #include "support/convert.h"
36 #include "support/FileFilterList.h"
37 #include "support/filetools.h"
38 #include "support/lstrings.h"
39 #include "support/lyxlib.h"
40 #include "support/os.h"
41 #include "support/Package.h"
42 #include "support/types.h"
43
44 #include <boost/bind.hpp>
45
46 #include <QCheckBox>
47 #include <QCloseEvent>
48 #include <QLabel>
49 #include <QLineEdit>
50 #include <QPushButton>
51 #include <QValidator>
52
53 #include <algorithm>
54 #include <cmath>
55 #include <utility>
56
57 #ifndef CXX_GLOBAL_CSTD
58 using std::floor;
59 #endif
60 using std::find;
61 using std::vector;
62 using std::string;
63 using std::transform;
64 using std::make_pair;
65 using std::pair;
66 using std::vector;
67
68 namespace lyx {
69 namespace frontend {
70
71 using support::addName;
72 using support::FileFilterList;
73 using support::FileName;
74 using support::float_equal;
75 using support::makeAbsPath;
76 using support::os::internal_path;
77 using support::package;
78 using support::readBB_from_PSFile;
79 using support::token;
80
81
82 //FIXME setAutoTextCB should really take an argument, as indicated, that
83 //determines what text is to be written for "auto". But making
84 //that work involves more extensive revisions than we now want
85 //to make, since "auto" also appears in updateContents() (see
86 //GuiGraphics.cpp).
87 //The right way to do this, I think, would be to define a class
88 //checkedLengthSet (and a partnering labeledLengthSete) that encapsulated
89 //the checkbox, line edit, and length combo together, and then made e.g.
90 //lengthToWidgets, widgetsToLength, etc, all public methods of that class.
91 //Perhaps even the validator could be exposed through it.
92 /**
93  * sets a checkbox-line edit-length combo group, using "text" if the
94  * checkbox is unchecked and clearing the line edit if it previously
95  * said "text".
96 */
97 static void setAutoTextCB(QCheckBox * checkBox, QLineEdit * lineEdit,
98         LengthCombo * lengthCombo/*, string text = "auto"*/)
99 {
100         if (!checkBox->isChecked())
101                 lengthToWidgets(lineEdit, lengthCombo,
102                                 "auto", lengthCombo->currentLengthItem());
103         else if (lineEdit->text() == "auto")
104                 lengthToWidgets(lineEdit, lengthCombo, string(),
105                                 lengthCombo->currentLengthItem());
106 }
107
108 template<class Pair>
109 vector<typename Pair::first_type> const
110 getFirst(vector<Pair> const & pr)
111 {
112         vector<typename Pair::first_type> tmp(pr.size());
113         transform(pr.begin(), pr.end(), tmp.begin(),
114                   boost::bind(&Pair::first, _1));
115         return tmp;
116 }
117
118 ///
119 template<class Pair>
120 vector<typename Pair::second_type> const
121 getSecond(vector<Pair> const & pr)
122 {
123          vector<typename Pair::second_type> tmp(pr.size());
124          transform(pr.begin(), pr.end(), tmp.begin(),
125                    boost::bind(&Pair::second, _1));
126          return tmp;
127 }
128
129 /// The (tranlated) GUI std::string and it's LaTeX equivalent.
130 typedef std::pair<docstring, std::string> RotationOriginPair;
131 ///
132 std::vector<RotationOriginPair> getRotationOriginData();
133
134
135 GuiGraphics::GuiGraphics(GuiView & lv)
136         : GuiDialog(lv, "graphics")
137 {
138         setupUi(this);
139         setViewTitle(_("Graphics"));
140
141         //main buttons
142         connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
143         connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
144         connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
145         connect(restorePB, SIGNAL(clicked()), this, SLOT(slotRestore()));
146
147         //graphics pane
148         connect(filename, SIGNAL(textChanged(const QString &)),
149                 this, SLOT(change_adaptor()));
150         connect(WidthCB, SIGNAL( clicked()),
151                 this, SLOT(change_adaptor()));
152         connect(HeightCB, SIGNAL( clicked()),
153                 this, SLOT(change_adaptor()));
154         connect(Width, SIGNAL(textChanged(const QString &)),
155                 this, SLOT(change_adaptor()));
156         connect(Height, SIGNAL(textChanged(const QString &)),
157                 this, SLOT(change_adaptor()));
158         connect(heightUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
159                 this, SLOT(change_adaptor()));
160         connect(widthUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
161                 this, SLOT(change_adaptor()));
162         connect(aspectratio, SIGNAL(stateChanged(int)),
163                 this, SLOT(change_adaptor()));
164         connect(angle, SIGNAL(textChanged(const QString &)),
165                 this, SLOT(change_adaptor()));
166         connect(origin, SIGNAL(activated(int)),
167                 this, SLOT(change_adaptor()));
168         connect(scaleCB, SIGNAL(clicked()),
169                 this, SLOT(change_adaptor()));
170         connect(Scale, SIGNAL(textChanged(const QString &)),
171                 this, SLOT(change_adaptor()));
172         connect(rotateOrderCB, SIGNAL(clicked()),
173                 this, SLOT(change_adaptor()));
174
175         filename->setValidator(new PathValidator(true, filename));
176         setFocusProxy(filename);
177
178         QDoubleValidator * scaleValidator = new DoubleAutoValidator(Scale);
179         scaleValidator->setBottom(0);
180         scaleValidator->setDecimals(256); //I guess that will do
181         Scale->setValidator(scaleValidator);
182         Height->setValidator(unsignedLengthAutoValidator(Height));
183         Width->setValidator(unsignedLengthAutoValidator(Width));
184         angle->setValidator(new QDoubleValidator(-360, 360, 2, angle));
185
186         //clipping pane
187         connect(clip, SIGNAL(stateChanged(int)),
188                 this, SLOT(change_adaptor()));
189         connect(lbY, SIGNAL(textChanged(const QString&)),
190                 this, SLOT(change_bb()));
191         connect(lbYunit, SIGNAL(activated(int)),
192                 this, SLOT(change_bb()));
193         connect(rtY, SIGNAL(textChanged(const QString&)),
194                 this, SLOT(change_bb()));
195         connect(rtYunit, SIGNAL(activated(int)),
196                 this, SLOT(change_bb()));
197         connect(lbX, SIGNAL(textChanged(const QString&)),
198                 this, SLOT(change_bb()));
199         connect(lbXunit, SIGNAL(activated(int)),
200                 this, SLOT(change_bb()));
201         connect(rtX, SIGNAL(textChanged(const QString&)),
202                 this, SLOT(change_bb()));
203         connect(rtXunit, SIGNAL(activated(int)),
204                 this, SLOT(change_bb()));
205         connect(getPB, SIGNAL(clicked()),
206                 this, SLOT(change_adaptor()));
207
208         lbX->setValidator(new QDoubleValidator(lbX));
209         lbY->setValidator(new QDoubleValidator(lbY));
210         rtX->setValidator(new QDoubleValidator(rtX));
211         rtY->setValidator(new QDoubleValidator(rtY));
212
213         //extra options pane
214         connect(latexoptions, SIGNAL(textChanged(const QString&)),
215                 this, SLOT(change_adaptor()));
216         connect(draftCB, SIGNAL(stateChanged(int)),
217                 this, SLOT(change_adaptor()));
218         connect(unzipCB, SIGNAL(stateChanged(int)),
219                 this, SLOT(change_adaptor()));
220         // FIXME: we should connect to clicked() when we move to Qt 4.2 because
221         // the toggled(bool) signal is also trigged when we update the widgets
222         // (rgh-4/07) this isn't as much or a problem as it was, because we're now
223         // using blockSignals() to keep from triggering that signal when we call
224         // setChecked(). Note, too, that clicked() would get called whenever it
225         // is clicked, even right clicked (I think), not just whenever it is
226         // toggled.
227         connect(subfigure, SIGNAL(toggled(bool)),
228                 this, SLOT(change_adaptor()));
229         connect(subcaption, SIGNAL(textChanged(const QString&)),
230                 this, SLOT(change_adaptor()));
231         connect(displayGB, SIGNAL(toggled(bool)),
232                 this, SLOT(change_adaptor()));
233         connect(showCB, SIGNAL(currentIndexChanged(int)),
234                 this, SLOT(change_adaptor()));
235         connect(displayscale, SIGNAL(textChanged(const QString&)),
236                 this, SLOT(change_adaptor()));
237         displayscale->setValidator(new QIntValidator(displayscale));
238
239         bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
240         bc().setOK(okPB);
241         bc().setApply(applyPB);
242         bc().setRestore(restorePB);
243         bc().setCancel(closePB);
244
245         bc().addReadOnly(latexoptions);
246         bc().addReadOnly(subfigure);
247         bc().addReadOnly(filenameL);
248         bc().addReadOnly(filename);
249         bc().addReadOnly(browsePB);
250         bc().addReadOnly(unzipCB);
251         bc().addReadOnly(bbFrame);
252         bc().addReadOnly(draftCB);
253         bc().addReadOnly(clip);
254         bc().addReadOnly(unzipCB);
255         bc().addReadOnly(displayGB);
256         bc().addReadOnly(sizeGB);
257         bc().addReadOnly(rotationGB);
258         bc().addReadOnly(latexoptions);
259         bc().addReadOnly(getPB);
260         bc().addReadOnly(rotateOrderCB);
261
262         // initialize the length validator
263         bc().addCheckedLineEdit(Scale, scaleCB);
264         bc().addCheckedLineEdit(Width, WidthCB);
265         bc().addCheckedLineEdit(Height, HeightCB);
266         bc().addCheckedLineEdit(displayscale, scaleLA);
267         bc().addCheckedLineEdit(angle, angleL);
268         bc().addCheckedLineEdit(lbX, xL);
269         bc().addCheckedLineEdit(lbY, yL);
270         bc().addCheckedLineEdit(rtX, xL_2);
271         bc().addCheckedLineEdit(rtY, yL_2);
272         bc().addCheckedLineEdit(filename, filenameL);
273 }
274
275
276 void GuiGraphics::change_adaptor()
277 {
278         changed();
279 }
280
281
282 void GuiGraphics::change_bb()
283 {
284         bbChanged = true;
285         LYXERR(Debug::GRAPHICS, "[bb_Changed set to true]");
286         changed();
287 }
288
289
290 void GuiGraphics::closeEvent(QCloseEvent * e)
291 {
292         slotClose();
293         GuiDialog::closeEvent(e);
294 }
295
296
297 void GuiGraphics::on_browsePB_clicked()
298 {
299         docstring const str = browse(qstring_to_ucs4(filename->text()));
300         if (!str.empty()) {
301                 filename->setText(toqstr(str));
302                 embedCB->setCheckState(Qt::Unchecked);
303                 changed();
304         }
305 }
306
307
308 void GuiGraphics::on_getPB_clicked()
309 {
310         getBB();
311 }
312
313
314 void GuiGraphics::on_editPB_clicked()
315 {
316         editGraphics();
317 }
318
319
320 void GuiGraphics::on_filename_textChanged(const QString & filename)
321 {
322         editPB->setDisabled(filename.isEmpty());
323 }
324
325
326 void GuiGraphics::setAutoText()
327 {
328         if (scaleCB->isChecked())
329                 return;
330         if (!Scale->isEnabled() && Scale->text() != "100")
331                 Scale->setText(QString("auto"));
332
333         setAutoTextCB(WidthCB, Width, widthUnit);
334         setAutoTextCB(HeightCB, Height, heightUnit);
335 }
336
337
338 void GuiGraphics::on_scaleCB_toggled(bool setScale)
339 {
340         Scale->setEnabled(setScale);
341         if (setScale) {
342                 Scale->setText("100");
343                 Scale->setFocus(Qt::OtherFocusReason);
344         }
345
346         WidthCB->setDisabled(setScale);
347         WidthCB->blockSignals(true);
348         WidthCB->setChecked(false);
349         WidthCB->blockSignals(false);
350         Width->setEnabled(false);
351         widthUnit->setEnabled(false);
352
353         HeightCB->setDisabled(setScale);
354         HeightCB->blockSignals(true);
355         HeightCB->setChecked(false);
356         HeightCB->blockSignals(false);
357         Height->setEnabled(false);
358         heightUnit->setEnabled(false);
359
360         aspectratio->setDisabled(true);
361         aspectratio->setChecked(true);
362
363         rotateOrderCB->setEnabled((WidthCB->isChecked() ||
364                                  HeightCB->isChecked() ||
365                                  scaleCB->isChecked()) &&
366                                  (angle->text() != "0"));
367
368         setAutoText();
369 }
370
371
372 void GuiGraphics::on_WidthCB_toggled(bool setWidth)
373 {
374         Width->setEnabled(setWidth);
375         widthUnit->setEnabled(setWidth);
376         if (setWidth)
377                 Width->setFocus(Qt::OtherFocusReason);
378
379         bool const setHeight = HeightCB->isChecked();
380         aspectratio->setEnabled(setWidth && setHeight);
381         aspectratio->blockSignals(true);
382         aspectratio->setChecked(!(setWidth && setHeight));
383         aspectratio->blockSignals(false);
384
385         scaleCB->setEnabled(!setWidth && !setHeight);
386         //already will be unchecked, so don't need to do that
387         Scale->setEnabled((!setWidth && !setHeight) //=scaleCB->isEnabled()
388                         && scaleCB->isChecked()); //should be false, but let's check
389         rotateOrderCB->setEnabled((setWidth || setHeight ||
390                                  scaleCB->isChecked()) &&
391                                  (angle->text() != "0"));
392
393         setAutoText();
394 }
395
396
397 void GuiGraphics::on_HeightCB_toggled(bool setHeight)
398 {
399         Height->setEnabled(setHeight);
400         heightUnit->setEnabled(setHeight);
401         if (setHeight)
402                 Height->setFocus(Qt::OtherFocusReason);
403
404         bool const setWidth = WidthCB->isChecked();
405         aspectratio->setEnabled(setWidth && setHeight);
406         aspectratio->blockSignals(true);
407         aspectratio->setChecked(!(setWidth && setHeight));
408         aspectratio->blockSignals(false);
409
410         scaleCB->setEnabled(!setWidth && !setHeight);
411         //already unchecked
412         Scale->setEnabled((!setWidth && !setHeight) //=scaleCB->isEnabled()
413                 && scaleCB->isChecked()); //should be false
414         rotateOrderCB->setEnabled((setWidth || setHeight ||
415                                  scaleCB->isChecked()) &&
416                                  (angle->text() != "0"));
417
418         setAutoText();
419 }
420
421
422 void GuiGraphics::on_angle_textChanged(const QString & filename)
423 {
424         rotateOrderCB->setEnabled((WidthCB->isChecked() ||
425                                  HeightCB->isChecked() ||
426                                  scaleCB->isChecked()) &&
427                                  (filename != "0"));
428 }
429
430 // returns the number of the string s in the vector v
431 static int getItemNo(const vector<string> & v, string const & s)
432 {
433         vector<string>::const_iterator cit =
434                     find(v.begin(), v.end(), s);
435         return (cit != v.end()) ? int(cit - v.begin()) : 0;
436 }
437
438
439 void GuiGraphics::updateContents()
440 {
441         // clear and fill in the comboboxes
442         vector<string> const bb_units = frontend::getBBUnits();
443         lbXunit->clear();
444         lbYunit->clear();
445         rtXunit->clear();
446         rtYunit->clear();
447         for (vector<string>::const_iterator it = bb_units.begin();
448             it != bb_units.end(); ++it) {
449                 lbXunit->addItem(toqstr(*it));
450                 lbYunit->addItem(toqstr(*it));
451                 rtXunit->addItem(toqstr(*it));
452                 rtYunit->addItem(toqstr(*it));
453         }
454
455         InsetGraphicsParams & igp = params_;
456
457         // set the right default unit
458         Length::UNIT unitDefault = Length::CM;
459         switch (lyxrc.default_papersize) {
460                 case PAPER_USLETTER:
461                 case PAPER_USLEGAL:
462                 case PAPER_USEXECUTIVE:
463                         unitDefault = Length::IN;
464                         break;
465                 default:
466                         break;
467         }
468
469         string const name =
470                 igp.filename.outputFilename(bufferFilepath());
471         filename->setText(toqstr(name));
472     embedCB->setCheckState(igp.filename.embedded() ? Qt::Checked : Qt::Unchecked);
473
474         // set the bounding box values
475         if (igp.bb.empty()) {
476                 string const bb = readBB(igp.filename.absFilename());
477                 // the values from the file always have the bigpoint-unit bp
478                 lbX->setText(toqstr(token(bb, ' ', 0)));
479                 lbY->setText(toqstr(token(bb, ' ', 1)));
480                 rtX->setText(toqstr(token(bb, ' ', 2)));
481                 rtY->setText(toqstr(token(bb, ' ', 3)));
482                 lbXunit->setCurrentIndex(0);
483                 lbYunit->setCurrentIndex(0);
484                 rtXunit->setCurrentIndex(0);
485                 rtYunit->setCurrentIndex(0);
486                 bbChanged = false;
487         } else {
488                 // get the values from the inset
489                 Length anyLength;
490                 string const xl = token(igp.bb, ' ', 0);
491                 string const yl = token(igp.bb, ' ', 1);
492                 string const xr = token(igp.bb, ' ', 2);
493                 string const yr = token(igp.bb, ' ', 3);
494                 if (isValidLength(xl, &anyLength)) {
495                         lbX->setText(toqstr(convert<string>(anyLength.value())));
496                         string const unit(unit_name[anyLength.unit()]);
497                         lbXunit->setCurrentIndex(getItemNo(bb_units, unit));
498                 } else {
499                         lbX->setText(toqstr(xl));
500                 }
501                 if (isValidLength(yl, &anyLength)) {
502                         lbY->setText(toqstr(convert<string>(anyLength.value())));
503                         string const unit(unit_name[anyLength.unit()]);
504                         lbYunit->setCurrentIndex(getItemNo(bb_units, unit));
505                 } else {
506                         lbY->setText(toqstr(xl));
507                 }
508                 if (isValidLength(xr, &anyLength)) {
509                         rtX->setText(toqstr(convert<string>(anyLength.value())));
510                         string const unit(unit_name[anyLength.unit()]);
511                         rtXunit->setCurrentIndex(getItemNo(bb_units, unit));
512                 } else {
513                         rtX->setText(toqstr(xl));
514                 }
515                 if (isValidLength(yr, &anyLength)) {
516                         rtY->setText(toqstr(convert<string>(anyLength.value())));
517                         string const unit(unit_name[anyLength.unit()]);
518                         rtYunit->setCurrentIndex(getItemNo(bb_units, unit));
519                 } else {
520                         rtY->setText(toqstr(xl));
521                 }
522                 bbChanged = true;
523         }
524
525         // Update the draft and clip mode
526         draftCB->setChecked(igp.draft);
527         clip->setChecked(igp.clip);
528         unzipCB->setChecked(igp.noUnzip);
529
530         // Update the subcaption check button and input field
531         subfigure->setChecked(igp.subcaption);
532         subcaption->setText(toqstr(igp.subcaptionText));
533
534         int item = 0;
535         switch (igp.display) {
536                 case graphics::DefaultDisplay: item = 0; break;
537                 case graphics::MonochromeDisplay: item = 1; break;
538                 case graphics::GrayscaleDisplay: item = 2; break;
539                 case graphics::ColorDisplay: item = 3; break;
540                 case graphics::NoDisplay: item = 0; break;
541         }
542         showCB->setCurrentIndex(item);
543         displayscale->setText(toqstr(convert<string>(igp.lyxscale)));
544         displayGB->setChecked(igp.display != graphics::NoDisplay);
545
546         // the output section (width/height)
547
548         Scale->setText(toqstr(igp.scale));
549         //igp.scale defaults to 100, so we treat it as empty
550         bool const scaleChecked = !igp.scale.empty() && igp.scale != "100";
551         scaleCB->blockSignals(true);
552         scaleCB->setChecked(scaleChecked);
553         scaleCB->blockSignals(false);
554         Scale->setEnabled(scaleChecked);
555
556         lengthAutoToWidgets(Width, widthUnit, igp.width,
557                 unitDefault);
558         bool const widthChecked = !Width->text().isEmpty() &&
559                 Width->text() != "auto";
560         WidthCB->blockSignals(true);
561         WidthCB->setChecked(widthChecked);
562         WidthCB->blockSignals(false);
563         Width->setEnabled(widthChecked);
564         widthUnit->setEnabled(widthChecked);
565
566         lengthAutoToWidgets(Height, heightUnit, igp.height,
567                 unitDefault);
568         bool const heightChecked = !Height->text().isEmpty()
569                 && Height->text() != "auto";
570         HeightCB->blockSignals(true);
571         HeightCB->setChecked(heightChecked);
572         HeightCB->blockSignals(false);
573         Height->setEnabled(heightChecked);
574         heightUnit->setEnabled(heightChecked);
575
576         scaleCB->setEnabled(!widthChecked && !heightChecked);
577         WidthCB->setEnabled(!scaleChecked);
578         HeightCB->setEnabled(!scaleChecked);
579         aspectratio->setEnabled(widthChecked && heightChecked);
580
581         setAutoText();
582
583         angle->setText(toqstr(igp.rotateAngle));
584         rotateOrderCB->setChecked(igp.scaleBeforeRotation);
585
586         rotateOrderCB->setEnabled( (widthChecked || heightChecked || scaleChecked)
587                 && igp.rotateAngle != "0");
588
589         origin->clear();
590
591         vector<RotationOriginPair> origindata = getRotationOriginData();
592         vector<docstring> const origin_lang = getFirst(origindata);
593         origin_ltx = getSecond(origindata);
594
595         for (vector<docstring>::const_iterator it = origin_lang.begin();
596             it != origin_lang.end(); ++it)
597                 origin->addItem(toqstr(*it));
598
599         if (!igp.rotateOrigin.empty())
600                 origin->setCurrentIndex(
601                         getItemNo(origin_ltx, igp.rotateOrigin));
602         else
603                 origin->setCurrentIndex(0);
604
605         // disable edit button when no filename is present
606         editPB->setDisabled(filename->text().isEmpty());
607
608         //// latex section
609         latexoptions->setText(toqstr(igp.special));
610 }
611
612
613 void GuiGraphics::applyView()
614 {
615         InsetGraphicsParams & igp = params_;
616
617         igp.filename.set(internal_path(fromqstr(filename->text())),
618                          bufferFilepath());
619         igp.filename.setEmbed(embedCB->checkState() == Qt::Checked);
620
621         // the bb section
622         igp.bb.erase();
623         if (bbChanged) {
624                 string bb;
625                 string lbXs = fromqstr(lbX->text());
626                 string lbYs = fromqstr(lbY->text());
627                 string rtXs = fromqstr(rtX->text());
628                 string rtYs = fromqstr(rtY->text());
629                 int bb_sum =
630                         convert<int>(lbXs) + convert<int>(lbYs) +
631                         convert<int>(rtXs) + convert<int>(rtXs);
632                 if (bb_sum) {
633                         if (lbXs.empty())
634                                 bb = "0 ";
635                         else
636                                 bb = lbXs + fromqstr(lbXunit->currentText()) + ' ';
637                         if (lbYs.empty())
638                                 bb += "0 ";
639                         else
640                                 bb += (lbYs + fromqstr(lbYunit->currentText()) + ' ');
641                         if (rtXs.empty())
642                                 bb += "0 ";
643                         else
644                                 bb += (rtXs + fromqstr(rtXunit->currentText()) + ' ');
645                         if (rtYs.empty())
646                                 bb += '0';
647                         else
648                                 bb += (rtYs + fromqstr(rtYunit->currentText()));
649                         igp.bb = bb;
650                 }
651         }
652
653         igp.draft = draftCB->isChecked();
654         igp.clip = clip->isChecked();
655         igp.subcaption = subfigure->isChecked();
656         igp.subcaptionText = fromqstr(subcaption->text());
657
658         switch (showCB->currentIndex()) {
659                 case 0: igp.display = graphics::DefaultDisplay; break;
660                 case 1: igp.display = graphics::MonochromeDisplay; break;
661                 case 2: igp.display = graphics::GrayscaleDisplay; break;
662                 case 3: igp.display = graphics::ColorDisplay; break;
663                 default:;
664         }
665
666         if (!displayGB->isChecked())
667                 igp.display = graphics::NoDisplay;
668
669         //the graphics section
670         if (scaleCB->isChecked() && !Scale->text().isEmpty()) {
671                 igp.scale = fromqstr(Scale->text());
672                 igp.width = Length("0pt");
673                 igp.height = Length("0pt");
674                 igp.keepAspectRatio = false;
675         } else {
676                 igp.scale = string();
677                 igp.width = WidthCB->isChecked() ?
678                         //Note that this works even if Width is "auto", since in
679                         //that case we get "0pt".
680                         Length(widgetsToLength(Width, widthUnit)):
681                         Length("0pt");
682                 igp.height = HeightCB->isChecked() ?
683                         Length(widgetsToLength(Height, heightUnit)) :
684                         Length("0pt");
685                 igp.keepAspectRatio = aspectratio->isEnabled() &&
686                         aspectratio->isChecked() &&
687                         igp.width.value() > 0 && igp.height.value() > 0;
688         }
689
690         igp.noUnzip = unzipCB->isChecked();
691         igp.lyxscale = displayscale->text().toInt();
692         igp.rotateAngle = fromqstr(angle->text());
693
694         double rotAngle = convert<double>(igp.rotateAngle);
695         if (std::abs(rotAngle) > 360.0) {
696                 rotAngle -= 360.0 * floor(rotAngle / 360.0);
697                 igp.rotateAngle = convert<string>(rotAngle);
698         }
699
700         // save the latex name for the origin. If it is the default
701         // then origin_ltx returns ""
702         igp.rotateOrigin = origin_ltx[origin->currentIndex()];
703         igp.scaleBeforeRotation = rotateOrderCB->isChecked();
704
705         // more latex options
706         igp.special = fromqstr(latexoptions->text());
707 }
708
709
710 void GuiGraphics::getBB()
711 {
712         string const fn = fromqstr(filename->text());
713         if (fn.empty())
714                 return;
715         string const bb = readBB(fn);
716         bbChanged = false;
717         if (bb.empty())
718                 return;
719         lbX->setText(toqstr(token(bb, ' ', 0)));
720         lbY->setText(toqstr(token(bb, ' ', 1)));
721         rtX->setText(toqstr(token(bb, ' ', 2)));
722         rtY->setText(toqstr(token(bb, ' ', 3)));
723         // the default units for the bb values when reading
724         // it from the file
725         lbXunit->setCurrentIndex(0);
726         lbYunit->setCurrentIndex(0);
727         rtXunit->setCurrentIndex(0);
728         rtYunit->setCurrentIndex(0);
729 }
730
731
732 bool GuiGraphics::isValid()
733 {
734         return !filename->text().isEmpty();
735 }
736
737
738 bool GuiGraphics::initialiseParams(string const & data)
739 {
740         InsetGraphicsMailer::string2params(data, buffer(), params_);
741         return true;
742 }
743
744
745 void GuiGraphics::clearParams()
746 {
747         params_ = InsetGraphicsParams();
748 }
749
750
751 void GuiGraphics::dispatchParams()
752 {
753         InsetGraphicsParams tmp_params(params_);
754         string const lfun =
755                 InsetGraphicsMailer::params2string(tmp_params, buffer());
756         dispatch(FuncRequest(getLfun(), lfun));
757 }
758
759
760 docstring const GuiGraphics::browse(docstring const & in_name) const
761 {
762         docstring const title = _("Select graphics file");
763
764         // Does user clipart directory exist?
765         string clipdir = addName(package().user_support().absFilename(), "clipart");
766         FileName clip(clipdir);
767
768         // bail out to system clipart directory
769         if (!(clip.exists() && clip.isDirectory()))
770                 clipdir = addName(package().system_support().absFilename(), "clipart");
771
772         return browseRelFile(in_name, from_utf8(bufferFilepath()),
773                 title, FileFilterList(), false, 
774                 _("Clipart|#C#c"), from_utf8(clipdir),
775                 _("Documents|#o#O"), from_utf8(lyxrc.document_path));
776 }
777
778
779 string const GuiGraphics::readBB(string const & file)
780 {
781         FileName const abs_file = makeAbsPath(file, bufferFilepath());
782
783         // try to get it from the file, if possible. Zipped files are
784         // unzipped in the readBB_from_PSFile-Function
785         string const bb = readBB_from_PSFile(abs_file);
786         if (!bb.empty())
787                 return bb;
788
789         // we don't, so ask the Graphics Cache if it has loaded the file
790         int width = 0;
791         int height = 0;
792
793         graphics::Cache & gc = graphics::Cache::get();
794         if (gc.inCache(abs_file)) {
795                 graphics::Image const * image = gc.item(abs_file)->image();
796
797                 if (image) {
798                         width  = image->width();
799                         height = image->height();
800                 }
801         }
802
803         return ("0 0 " + convert<string>(width) + ' ' + convert<string>(height));
804 }
805
806
807 bool GuiGraphics::isFilenameValid(string const & fname) const
808 {
809         // It may be that the filename is relative.
810         return makeAbsPath(fname, bufferFilepath()).isReadableFile();
811 }
812
813
814 void GuiGraphics::editGraphics()
815 {
816         applyView();
817         string const lfun =
818                 InsetGraphicsMailer::params2string(params_, buffer());
819         dispatch(FuncRequest(LFUN_GRAPHICS_EDIT, lfun));
820 }
821
822
823 namespace {
824
825 char const * const bb_units[] = { "bp", "cm", "mm", "in" };
826 size_t const bb_size = sizeof(bb_units) / sizeof(char *);
827
828 // These are the strings that are stored in the LyX file and which
829 // correspond to the LaTeX identifiers shown in the comments at the
830 // end of each line.
831 char const * const rorigin_lyx_strs[] = {
832         // the LaTeX default is leftBaseline
833         "",
834         "leftTop",  "leftBottom", "leftBaseline", // lt lb lB
835         "center", "centerTop", "centerBottom", "centerBaseline", // c ct cb cB
836         "rightTop", "rightBottom", "rightBaseline" }; // rt rb rB
837
838 // These are the strings, corresponding to the above, that the GUI should
839 // use. Note that they can/should be translated.
840 char const * const rorigin_gui_strs[] = {
841         N_("Default"),
842         N_("Top left"), N_("Bottom left"), N_("Baseline left"),
843         N_("Center"), N_("Top center"), N_("Bottom center"), N_("Baseline center"),
844         N_("Top right"), N_("Bottom right"), N_("Baseline right") };
845
846 size_t const rorigin_size = sizeof(rorigin_lyx_strs) / sizeof(char *);
847
848 } // namespace anon
849
850
851 vector<string> const getBBUnits()
852 {
853         return vector<string>(bb_units, bb_units + bb_size);
854 }
855
856
857 vector<RotationOriginPair> getRotationOriginData()
858 {
859         static vector<RotationOriginPair> data;
860         if (!data.empty())
861                 return data;
862
863         data.resize(rorigin_size);
864         for (size_type i = 0; i < rorigin_size; ++i) {
865                 data[i] = make_pair(_(rorigin_gui_strs[i]),
866                                     rorigin_lyx_strs[i]);
867         }
868
869         return data;
870 }
871
872
873 Dialog * createGuiGraphics(GuiView & lv) { return new GuiGraphics(lv); }
874
875
876 } // namespace frontend
877 } // namespace lyx
878
879 #include "GuiGraphics_moc.cpp"