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