]> git.lyx.org Git - features.git/blob - src/frontends/xforms/FormExternal.C
Handle Qt-style file filters like
[features.git] / src / frontends / xforms / FormExternal.C
1 /**
2  * \file FormExternal.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup
7  * \author John Levon
8  * \author Angus Leeming
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "FormExternal.h"
16 #include "forms/form_external.h"
17
18 #include "checkedwidgets.h"
19 #include "input_validators.h"
20 #include "Tooltips.h"
21 #include "xforms_helpers.h"
22 #include "xformsBC.h"
23
24 #include "controllers/ControlExternal.h"
25
26 #include "lengthcommon.h"
27 #include "lyxrc.h"
28
29 #include "insets/ExternalTemplate.h"
30 #include "insets/insetexternal.h"
31
32 #include "support/lstrings.h"
33 #include "support/lyxlib.h"
34 #include "support/tostr.h"
35
36 #include "lyx_forms.h"
37
38 namespace external = lyx::external;
39
40 using lyx::support::bformat;
41 using lyx::support::float_equal;
42 using lyx::support::getStringFromVector;
43 using lyx::support::isStrDbl;
44 using lyx::support::strToDbl;
45 using lyx::support::strToInt;
46 using lyx::support::token;
47 using lyx::support::trim;
48
49 using std::find;
50 using std::string;
51 using std::vector;
52
53
54 namespace {
55
56 LyXLength::UNIT defaultUnit()
57 {
58         LyXLength::UNIT default_unit = LyXLength::CM;
59         switch (lyxrc.default_papersize) {
60         case PAPER_USLETTER:
61         case PAPER_LEGALPAPER:
62         case PAPER_EXECUTIVEPAPER:
63                 default_unit = LyXLength::IN;
64                 break;
65         default:
66                 break;
67         }
68         return default_unit;
69 }
70
71
72 void setDisplay(FL_OBJECT * displayCB, FL_OBJECT * showCO, FL_OBJECT * scaleED,
73                 external::DisplayType display, unsigned int scale,
74                 bool read_only)
75 {
76         BOOST_ASSERT(displayCB && displayCB->objclass == FL_CHECKBUTTON);
77         BOOST_ASSERT(showCO && showCO->objclass == FL_CHOICE);
78         BOOST_ASSERT(scaleED && scaleED->objclass == FL_INPUT);
79
80         int item = 1;
81         switch (display) {
82         case external::DefaultDisplay:
83                 item = 1;
84                 break;
85         case external::MonochromeDisplay:
86                 item = 2;
87                 break;
88         case external::GrayscaleDisplay:
89                 item = 3;
90                 break;
91         case external::ColorDisplay:
92                 item = 4;
93                 break;
94         case external::PreviewDisplay:
95                 item = 5;
96                 break;
97         case external::NoDisplay:
98                 item = 1;
99                 break;
100         }
101
102         fl_set_choice(showCO, item);
103
104         bool const no_display = display == lyx::external::NoDisplay;
105         setEnabled(showCO, !no_display && !read_only);
106
107         fl_set_button(displayCB, !no_display);
108
109         fl_set_input(scaleED, tostr(scale).c_str());
110         setEnabled(scaleED, !no_display && !read_only);
111 }
112
113
114 void getDisplay(external::DisplayType & display,
115                 unsigned int & scale,
116                 FL_OBJECT * displayCB,
117                 FL_OBJECT * showCO,
118                 FL_OBJECT * scaleED)
119 {
120         BOOST_ASSERT(displayCB && displayCB->objclass == FL_CHECKBUTTON);
121         BOOST_ASSERT(showCO && showCO->objclass == FL_CHOICE);
122         BOOST_ASSERT(scaleED && scaleED->objclass == FL_INPUT);
123
124         switch (fl_get_choice(showCO)) {
125         case 1:
126                 display = external::DefaultDisplay;
127                 break;
128         case 2:
129                 display = external::MonochromeDisplay;
130                 break;
131         case 3:
132                 display = external::GrayscaleDisplay;
133                 break;
134         case 4:
135                 display = external::ColorDisplay;
136                 break;
137         case 5:
138                 display = external::PreviewDisplay;
139                 break;
140         }
141
142         if (!fl_get_button(displayCB))
143                 display = external::NoDisplay;
144
145         scale = strToInt(getString(scaleED));
146 }
147
148
149 void setRotation(FL_OBJECT * angleED, FL_OBJECT * originCO,
150                  external::RotationData const & data)
151 {
152         BOOST_ASSERT(angleED && angleED->objclass == FL_INPUT);
153         BOOST_ASSERT(originCO && originCO->objclass == FL_CHOICE);
154
155         fl_set_choice(originCO, 1 + int(data.origin()));
156         fl_set_input(angleED, tostr(data.angle()).c_str());
157 }
158
159
160 void getRotation(external::RotationData & data,
161                  FL_OBJECT * angleED, FL_OBJECT * originCO)
162 {
163         BOOST_ASSERT(angleED && angleED->objclass == FL_INPUT);
164         BOOST_ASSERT(originCO && originCO->objclass == FL_CHOICE);
165
166         typedef external::RotationData::OriginType OriginType;
167
168         data.origin(static_cast<OriginType>(fl_get_choice(originCO) - 1));
169         data.angle(strToDbl(getString(angleED)));
170 }
171
172
173 void setSize(FL_OBJECT * widthED, FL_OBJECT * widthUnitCO,
174              FL_OBJECT * heightED, FL_OBJECT * heightUnitCO,
175              FL_OBJECT * aspectratioCB,
176              external::ResizeData const & data)
177 {
178         BOOST_ASSERT(widthED && widthED->objclass == FL_INPUT);
179         BOOST_ASSERT(widthUnitCO && widthUnitCO->objclass == FL_CHOICE);
180         BOOST_ASSERT(heightED && heightED->objclass == FL_INPUT);
181         BOOST_ASSERT(heightUnitCO && heightUnitCO->objclass == FL_CHOICE);
182         BOOST_ASSERT(aspectratioCB &&
183                      aspectratioCB->objclass == FL_CHECKBUTTON);
184
185         bool using_scale = data.usingScale();
186         double scale =  data.scale;
187         if (data.no_resize()) {
188                 // Everything is zero, so default to this!
189                 using_scale = true;
190                 scale = 100;
191         }
192
193         if (using_scale) {
194                 fl_set_input(widthED, tostr(scale).c_str());
195                 fl_set_choice(widthUnitCO, 1);
196         } else {
197                 fl_set_input(widthED, tostr(data.width.value()).c_str());
198                 // Because 'Scale' is position 1...
199                 // Note also that width cannot be zero here, so
200                 // we don't need to worry about the default unit.
201                 fl_set_choice(widthUnitCO, data.width.unit() + 2);
202         }
203
204         string const h = data.height.zero() ? string() : data.height.asString();
205         LyXLength::UNIT default_unit = data.width.zero() ?
206                 defaultUnit() : data.width.unit();
207         updateWidgetsFromLengthString(heightED, heightUnitCO,
208                                       h, stringFromUnit(default_unit));
209
210         setEnabled(heightED, !using_scale);
211         setEnabled(heightUnitCO, !using_scale);
212
213         fl_set_button(aspectratioCB, data.keepAspectRatio);
214
215         bool const disable_aspectRatio = using_scale ||
216                 data.width.zero() || data.height.zero();
217         setEnabled(aspectratioCB, !disable_aspectRatio);
218 }
219
220
221 void getSize(external::ResizeData & data,
222              FL_OBJECT * widthED, FL_OBJECT * widthUnitCO,
223              FL_OBJECT * heightED, FL_OBJECT * heightUnitCO,
224              FL_OBJECT * aspectratioCB)
225 {
226         BOOST_ASSERT(widthED && widthED->objclass == FL_INPUT);
227         BOOST_ASSERT(widthUnitCO && widthUnitCO->objclass == FL_CHOICE);
228         BOOST_ASSERT(heightED && heightED->objclass == FL_INPUT);
229         BOOST_ASSERT(heightUnitCO && heightUnitCO->objclass == FL_CHOICE);
230         BOOST_ASSERT(aspectratioCB &&
231                      aspectratioCB->objclass == FL_CHECKBUTTON);
232
233         string const width = getString(widthED);
234
235         if (fl_get_choice(widthUnitCO) > 1) {
236                 // Subtract one, because scale is 1.
237                 int const unit = fl_get_choice(widthUnitCO) - 1;
238
239                 LyXLength w;
240                 if (isValidLength(width, &w))
241                         data.width = w;
242                 else if (isStrDbl(width))
243                         data.width = LyXLength(strToDbl(width),
244                                            static_cast<LyXLength::UNIT>(unit));
245                 else
246                         data.width = LyXLength();
247
248                 data.scale = 0.0;
249
250         } else {
251                 // scaling instead of a width
252                 data.scale = strToDbl(width);
253                 data.width = LyXLength();
254         }
255
256         data.height = LyXLength(getLengthFromWidgets(heightED, heightUnitCO));
257
258         data.keepAspectRatio = fl_get_button(aspectratioCB);
259 }
260
261
262 void setCrop(FL_OBJECT * clipCB,
263              FL_OBJECT * xlED, FL_OBJECT * ybED,
264              FL_OBJECT * xrED, FL_OBJECT * ytED,
265              external::ClipData const & data)
266 {
267         BOOST_ASSERT(clipCB && clipCB->objclass == FL_CHECKBUTTON);
268         BOOST_ASSERT(xlED && xlED->objclass == FL_INPUT);
269         BOOST_ASSERT(ybED && ybED->objclass == FL_INPUT);
270         BOOST_ASSERT(xrED && xrED->objclass == FL_INPUT);
271         BOOST_ASSERT(ytED && ytED->objclass == FL_INPUT);
272
273         fl_set_button(clipCB, data.clip);
274         lyx::graphics::BoundingBox const & bbox = data.bbox;
275         fl_set_input(xlED, tostr(bbox.xl).c_str());
276         fl_set_input(ybED, tostr(bbox.yb).c_str());
277         fl_set_input(xrED, tostr(bbox.xr).c_str());
278         fl_set_input(ytED, tostr(bbox.yt).c_str());
279 }
280
281
282 void getCrop(external::ClipData & data,
283              FL_OBJECT * clipCB,
284              FL_OBJECT * xlED, FL_OBJECT * ybED,
285              FL_OBJECT * xrED, FL_OBJECT * ytED,
286              bool bb_changed)
287 {
288         BOOST_ASSERT(clipCB && clipCB->objclass == FL_CHECKBUTTON);
289         BOOST_ASSERT(xlED && xlED->objclass == FL_INPUT);
290         BOOST_ASSERT(ybED && ybED->objclass == FL_INPUT);
291         BOOST_ASSERT(xrED && xrED->objclass == FL_INPUT);
292         BOOST_ASSERT(ytED && ytED->objclass == FL_INPUT);
293
294         data.clip = fl_get_button(clipCB);
295
296         if (!bb_changed)
297                 return;
298
299         data.bbox.xl = strToInt(getString(xlED));
300         data.bbox.yb = strToInt(getString(ybED));
301         data.bbox.xr = strToInt(getString(xrED));
302         data.bbox.yt = strToInt(getString(ytED));
303 }
304
305
306 void getExtra(external::ExtraData & data,
307               FormExternal::MapType const & extra)
308 {
309         typedef FormExternal::MapType MapType;
310         MapType::const_iterator it  = extra.begin();
311         MapType::const_iterator const end = extra.end();
312         for (; it != end; ++it)
313                 data.set(it->first, trim(it->second));
314 }
315
316 } // namespace anon
317
318
319 typedef FormController<ControlExternal, FormView<FD_external> > base_class;
320
321 FormExternal::FormExternal(Dialog & parent)
322         : base_class(parent, _("External Material"))
323 {}
324
325
326 void FormExternal::build()
327 {
328         dialog_.reset(build_external(this));
329         file_.reset(build_external_file(this));
330         lyxview_.reset(build_external_lyxview(this));
331         rotate_.reset(build_external_rotate(this));
332         scale_.reset(build_external_scale(this));
333         crop_.reset(build_external_crop(this));
334         options_.reset(build_external_options(this));
335
336         bcview().setOK(dialog_->button_ok);
337         bcview().setApply(dialog_->button_apply);
338         bcview().setCancel(dialog_->button_close);
339
340         bcview().addReadOnly(file_->input_file);
341         bcview().addReadOnly(file_->button_browse);
342         bcview().addReadOnly(file_->button_edit);
343         bcview().addReadOnly(file_->choice_template);
344         bcview().addReadOnly(file_->check_draft);
345
346         bcview().addReadOnly(lyxview_->check_show);
347         bcview().addReadOnly(lyxview_->choice_show);
348         bcview().addReadOnly(lyxview_->input_displayscale);
349
350         bcview().addReadOnly(rotate_->input_angle);
351         bcview().addReadOnly(rotate_->choice_origin);
352
353         bcview().addReadOnly(scale_->input_width);
354         bcview().addReadOnly(scale_->choice_width);
355         bcview().addReadOnly(scale_->input_height);
356         bcview().addReadOnly(scale_->choice_height);
357         bcview().addReadOnly(scale_->check_aspectratio);
358
359         bcview().addReadOnly(crop_->check_bbox);
360         bcview().addReadOnly(crop_->button_get_bbox);
361         bcview().addReadOnly(crop_->input_xr);
362         bcview().addReadOnly(crop_->input_yt);
363         bcview().addReadOnly(crop_->input_xl);
364         bcview().addReadOnly(crop_->input_yb);
365
366         bcview().addReadOnly(options_->choice_option);
367         bcview().addReadOnly(options_->input_option);
368
369         // initial setting
370 //      addCheckedPositiveFloat(bcview(), scale_->input_width);
371         // As I haven't written addCheckedPositiveFloat, we default to
372         // always checking that it is a valide LyXLength, even when
373         // I'm 'scaling'. No harm done, just not as strict as it might be.
374         addCheckedLyXLength(bcview(), scale_->input_width);
375         addCheckedLyXLength(bcview(), scale_->input_height);
376
377 //      addCheckedPositiveFloat(bcview(), input_displayscale);
378         fl_set_input_filter(lyxview_->input_displayscale,
379                             fl_unsigned_int_filter);
380
381         fl_set_input_filter(crop_->input_xr, fl_unsigned_int_filter);
382         fl_set_input_filter(crop_->input_yt, fl_unsigned_int_filter);
383         fl_set_input_filter(crop_->input_xl, fl_unsigned_int_filter);
384         fl_set_input_filter(crop_->input_yb, fl_unsigned_int_filter);
385
386         fl_set_input_return(file_->input_file,            FL_RETURN_CHANGED);
387         fl_set_input_return(lyxview_->input_displayscale, FL_RETURN_CHANGED);
388         fl_set_input_return(rotate_->input_angle,         FL_RETURN_CHANGED);
389         fl_set_input_return(scale_->input_width,          FL_RETURN_CHANGED);
390         fl_set_input_return(scale_->input_height,         FL_RETURN_CHANGED);
391         fl_set_input_return(crop_->input_xr,              FL_RETURN_CHANGED);
392         fl_set_input_return(crop_->input_yt,              FL_RETURN_CHANGED);
393         fl_set_input_return(crop_->input_xl,              FL_RETURN_CHANGED);
394         fl_set_input_return(crop_->input_yb,              FL_RETURN_CHANGED);
395         fl_set_input_return(options_->input_option,       FL_RETURN_CHANGED);
396
397         // Trigger an input event for cut&paste with middle mouse button.
398         setPrehandler(file_->input_file);
399         setPrehandler(lyxview_->input_displayscale);
400         setPrehandler(rotate_->input_angle);
401         setPrehandler(scale_->input_width);
402         setPrehandler(scale_->input_height);
403         setPrehandler(crop_->input_xr);
404         setPrehandler(crop_->input_yt);
405         setPrehandler(crop_->input_xl);
406         setPrehandler(crop_->input_yb);
407         setPrehandler(options_->input_option);
408
409         string const choice =
410                 ' ' + getStringFromVector(controller().getTemplates(), " | ") +
411                 ' ';
412         fl_addto_choice(file_->choice_template, choice.c_str());
413
414         string const display_list =
415                 _("Default|Monochrome|Grayscale|Color|Preview");
416         fl_addto_choice(lyxview_->choice_show, display_list.c_str());
417
418         // Fill the origins combo
419         typedef vector<external::RotationDataType> Origins;
420         Origins const & all_origins = external::all_origins();
421         for (Origins::size_type i = 0; i != all_origins.size(); ++i)
422                 fl_addto_choice(rotate_->choice_origin,
423                                 external::origin_gui_str(i).c_str());
424
425         string const width_list = bformat(_("Scale%%%%|%1$s"),
426                                           choice_Length_All);
427         fl_addto_choice(scale_->choice_width, width_list.c_str());
428
429         fl_addto_choice(scale_->choice_height, choice_Length_All.c_str());
430
431         // Set up the tooltips.
432         string str = _("The file you want to insert.");
433         tooltips().init(file_->input_file, str);
434         str = _("Browse the directories.");
435         tooltips().init(file_->button_browse, str);
436
437         str = _("Scale the image to inserted percentage value.");
438         tooltips().init(lyxview_->input_displayscale, str);
439         str = _("Select display mode for this image.");
440         tooltips().init(options_->choice_option, str);
441
442         // Stack tabs
443         tabmap_[FILETAB] =
444                 fl_addto_tabfolder(dialog_->tabfolder, _("File").c_str(),
445                                    file_->form);
446
447         tabmap_[LYXVIEWTAB] =
448                 fl_addto_tabfolder(dialog_->tabfolder, _("LyX View").c_str(),
449                                    lyxview_->form);
450         tabmap_[ROTATETAB] =
451                 fl_addto_tabfolder(dialog_->tabfolder, _("Rotate").c_str(),
452                                    rotate_->form);
453         tabmap_[SCALETAB] =
454                 fl_addto_tabfolder(dialog_->tabfolder, _("Scale").c_str(),
455                                    scale_->form);
456         tabmap_[CROPTAB] =
457                 fl_addto_tabfolder(dialog_->tabfolder, _("Crop").c_str(),
458                                    crop_->form);
459         tabmap_[OPTIONSTAB] =
460                 fl_addto_tabfolder(dialog_->tabfolder, _("Options").c_str(),
461                                    options_->form);
462 }
463
464
465 void FormExternal::update()
466 {
467         fl_set_folder_bynumber(dialog_->tabfolder, 1);
468         InsetExternalParams const & params = controller().params();
469
470         string const buffer_path = kernel().bufferFilepath();
471         string const name = params.filename.outputFilename(buffer_path);
472         fl_set_input(file_->input_file, name.c_str());
473
474         int ID = controller().getTemplateNumber(params.templatename());
475         if (ID < 0) ID = 0;
476         fl_set_choice(file_->choice_template, ID+1);
477
478         updateComboChange();
479
480         fl_set_button(file_->check_draft, params.draft);
481
482         setDisplay(lyxview_->check_show, lyxview_->choice_show,
483                    lyxview_->input_displayscale,
484                    params.display, params.lyxscale,
485                    kernel().isBufferReadonly());
486
487         setRotation(rotate_->input_angle, rotate_->choice_origin,
488                     params.rotationdata);
489
490         setSize(scale_->input_width, scale_->choice_width,
491                 scale_->input_height, scale_->choice_height,
492                 scale_->check_aspectratio,
493                 params.resizedata);
494
495         setCrop(crop_->check_bbox,
496                 crop_->input_xl, crop_->input_yb,
497                 crop_->input_xr, crop_->input_yt,
498                 params.clipdata);
499         controller().bbChanged(!params.clipdata.bbox.empty());
500 }
501
502
503 void FormExternal::updateComboChange()
504 {
505         namespace external = lyx::external;
506
507         int const choice = fl_get_choice(file_->choice_template) - 1;
508         external::Template templ = controller().getTemplate(choice);
509
510         // Update the help text
511         string const txt = formatted(templ.helpText,
512                                      file_->browser_template->w - 20);
513         fl_clear_browser(file_->browser_template);
514         fl_addto_browser(file_->browser_template, txt.c_str());
515         fl_set_browser_topline(file_->browser_template, 0);
516
517         // Ascertain which (if any) transformations the template supports
518         // and disable tabs hosting unsupported transforms.
519         typedef vector<external::TransformID> TransformIDs;
520         TransformIDs const transformIds = templ.transformIds;
521         TransformIDs::const_iterator tr_begin = transformIds.begin();
522         TransformIDs::const_iterator const tr_end = transformIds.end();
523
524         tabmap_[FILETAB];
525         tabmap_[LYXVIEWTAB];
526         tabmap_[ROTATETAB];
527         tabmap_[SCALETAB];
528         tabmap_[CROPTAB];
529         tabmap_[OPTIONSTAB];
530
531         bool found = find(tr_begin, tr_end, external::Rotate) != tr_end;
532         setEnabled(tabmap_[ROTATETAB], found);
533
534         found = find(tr_begin, tr_end, external::Resize) != tr_end;
535         setEnabled(tabmap_[SCALETAB], found);
536
537         found = find(tr_begin, tr_end, external::Clip) != tr_end;
538         setEnabled(tabmap_[CROPTAB], found);
539
540         found = find(tr_begin, tr_end, external::Extra) != tr_end;
541         setEnabled(tabmap_[OPTIONSTAB], found);
542
543         if (!found)
544                 return;
545
546         // Ascertain whether the template has any formats supporting
547         // the 'Extra' option
548         FL_OBJECT * const ob_input  = options_->input_option;
549         FL_OBJECT * const ob_choice = options_->choice_option;
550         extra_.clear();
551         fl_set_input(ob_input, "");
552         fl_clear_choice(ob_choice);
553
554         external::Template::Formats::const_iterator it  = templ.formats.begin();
555         external::Template::Formats::const_iterator end = templ.formats.end();
556         for (; it != end; ++it) {
557                 if (it->second.option_transformers.find(external::Extra) ==
558                     it->second.option_transformers.end())
559                         continue;
560                 string const format = it->first;
561                 string const opt = controller().params().extradata.get(format);
562                 fl_addto_choice(ob_choice, format.c_str());
563                 extra_[format] = opt;
564         }
565
566         bool const enabled = fl_get_choice_maxitems(ob_choice) > 0;
567
568         setEnabled(tabmap_[OPTIONSTAB], enabled);
569         setEnabled(ob_input,  enabled && !kernel().isBufferReadonly());
570         setEnabled(ob_choice, enabled);
571
572         if (enabled) {
573                 fl_set_choice(ob_choice, 1);
574                 string const format = fl_get_choice_text(ob_choice);
575                 fl_set_input(ob_input, extra_[format].c_str());
576         }
577 }
578
579
580 void FormExternal::apply()
581 {
582         InsetExternalParams params = controller().params();
583
584         string const buffer_path = kernel().bufferFilepath();
585         params.filename.set(getString(file_->input_file), buffer_path);
586
587         int const choice = fl_get_choice(file_->choice_template) - 1;
588         params.settemplate(controller().getTemplate(choice).lyxName);
589
590         params.draft = fl_get_button(file_->check_draft);
591
592         getDisplay(params.display, params.lyxscale,
593                    lyxview_->check_show, lyxview_->choice_show,
594                    lyxview_->input_displayscale);
595
596         if (isActive(tabmap_[ROTATETAB]))
597                 getRotation(params.rotationdata,
598                             rotate_->input_angle, rotate_->choice_origin);
599
600         if (isActive(tabmap_[SCALETAB]))
601                 getSize(params.resizedata,
602                         scale_->input_width, scale_->choice_width,
603                         scale_->input_height, scale_->choice_height,
604                         scale_->check_aspectratio);
605
606         if (isActive(tabmap_[CROPTAB]))
607                 getCrop(params.clipdata,
608                         crop_->check_bbox,
609                         crop_->input_xl, crop_->input_yb,
610                         crop_->input_xr, crop_->input_yt,
611                         controller().bbChanged());
612
613         if (isActive(tabmap_[OPTIONSTAB]))
614                 getExtra(params.extradata, extra_);
615
616         controller().setParams(params);
617 }
618
619
620 ButtonPolicy::SMInput FormExternal::input(FL_OBJECT * ob, long)
621 {
622         ButtonPolicy::SMInput result = ButtonPolicy::SMI_VALID;
623
624         if (ob == file_->choice_template) {
625
626                 // set to the chosen template
627                 updateComboChange();
628
629         } else if (ob == file_->button_browse) {
630
631                 string const in_name  = fl_get_input(file_->input_file);
632
633                 int const choice = fl_get_choice(file_->choice_template) - 1;
634                 string const template_name =
635                         controller().getTemplate(choice).lyxName;
636                 string const out_name =
637                         controller().browse(in_name, template_name);
638                 fl_set_input(file_->input_file, out_name.c_str());
639
640         } else if (ob == file_->button_edit) {
641                 controller().editExternal();
642                 result = ButtonPolicy::SMI_NOOP;
643
644         } else if (ob == lyxview_->check_show) {
645
646                 bool const checked = fl_get_button(ob);
647                 setEnabled(lyxview_->choice_show, checked);
648                 setEnabled(lyxview_->input_displayscale, checked);
649
650         } else if (ob == crop_->button_get_bbox) {
651
652                 getBB();
653
654         } else if (ob == scale_->input_width ||
655                    ob == scale_->input_height) {
656
657                 setEnabled(scale_->check_aspectratio,
658                            activateAspectratio());
659
660         } else if (ob == scale_->choice_width) {
661
662                 widthUnitChanged();
663
664         } else if (ob == crop_->input_xr ||
665                    ob == crop_->input_yt ||
666                    ob == crop_->input_xl ||
667                    ob == crop_->input_yb) {
668
669                 controller().bbChanged(true);
670
671         } else if (ob == options_->input_option) {
672
673                 string const format =
674                         fl_get_choice_text(options_->choice_option);
675                 extra_[format] = getString(options_->input_option);
676
677         } else if (ob == options_->choice_option) {
678
679                 string const format =
680                         fl_get_choice_text(options_->choice_option);
681                 fl_set_input(options_->input_option, extra_[format].c_str());
682                 result = ButtonPolicy::SMI_NOOP;
683         }
684
685         return result;
686 }
687
688
689 bool FormExternal::activateAspectratio() const
690 {
691         if (fl_get_choice(scale_->choice_width) == 1)
692                 return false;
693
694         string const wstr = getString(scale_->input_width);
695         if (wstr.empty())
696                 return false;
697         bool const wIsDbl = isStrDbl(wstr);
698         if (wIsDbl && float_equal(strToDbl(wstr), 0.0, 0.05))
699                 return false;
700         LyXLength l;
701         if (!wIsDbl && (!isValidLength(wstr, &l) || l.zero()))
702                 return false;
703
704         string const hstr = getString(scale_->input_height);
705         if (hstr.empty())
706                 return false;
707         bool const hIsDbl = isStrDbl(hstr);
708         if (hIsDbl && float_equal(strToDbl(hstr), 0.0, 0.05))
709                 return false;
710         if (!hIsDbl && (!isValidLength(hstr, &l) || l.zero()))
711                 return false;
712
713         return true;
714 }
715
716
717 void FormExternal::getBB()
718 {
719         fl_set_input(crop_->input_xl, "0");
720         fl_set_input(crop_->input_yb, "0");
721         fl_set_input(crop_->input_xr, "0");
722         fl_set_input(crop_->input_yt, "0");
723
724         string const filename = getString(file_->input_file);
725         if (filename.empty())
726                 return;
727
728         string const bb = controller().readBB(filename);
729         if (bb.empty())
730                 return;
731
732         fl_set_input(crop_->input_xl, token(bb, ' ', 0).c_str());
733         fl_set_input(crop_->input_yb, token(bb, ' ', 1).c_str());
734         fl_set_input(crop_->input_xr, token(bb, ' ', 2).c_str());
735         fl_set_input(crop_->input_yt, token(bb, ' ', 3).c_str());
736
737         controller().bbChanged(false);
738 }
739
740
741 void FormExternal::widthUnitChanged()
742 {
743         if (fl_get_choice(scale_->choice_width) == 1)
744                 return;
745
746         bool useHeight = fl_get_choice(scale_->choice_width) > 1;
747
748 //      if (useHeight)
749 //              widthED->setValidator(unsignedLengthValidator(widthED));
750 //      else
751 //              widthED->setValidator(new QDoubleValidator(0, 1000, 2, widthED));
752
753         setEnabled(scale_->input_height, useHeight);
754         setEnabled(scale_->choice_height, useHeight);
755 }