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