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