]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormParagraph.C
Bugfixes: checkboxes to radiobuttons (from J�rgen S) and remove a little
[lyx.git] / src / frontends / xforms / FormParagraph.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 2000-2001 The LyX Team.
7  *
8  *           @author Jürgen Vigna
9  *
10  *======================================================*/
11
12 #include <config.h>
13
14 #ifdef __GNUG_
15 #pragma implementation
16 #endif
17
18 #include FORMS_H_LOCATION
19
20 #include "FormParagraph.h"
21 #include "form_paragraph.h"
22 #include "Dialogs.h"
23 #include "Liason.h"
24 #include "LyXView.h"
25 #include "buffer.h"
26 #include "lyxtext.h"
27 #include "xforms_helpers.h"
28 #include "lyxrc.h" // to set the deafult length values
29 #include "BufferView.h"
30 #include "lyxtextclasslist.h"
31 #include "Spacing.h"
32 #include "ParagraphParameters.h"
33 #include "input_validators.h"
34 #include "helper_funcs.h"
35
36 #include "support/lstrings.h"
37
38 using Liason::setMinibuffer;
39 using SigC::slot;
40
41
42 FormParagraph::FormParagraph(LyXView * lv, Dialogs * d)
43         : FormBaseBD(lv, d, _("Paragraph Layout")), par_(0)
44 {
45     // let the dialog be shown
46     // This is a permanent connection so we won't bother
47     // storing a copy because we won't be disconnecting.
48     d->showParagraph.connect(slot(this, &FormParagraph::show));
49 }
50
51
52 void FormParagraph::connect()
53 {
54         cp_ = d_->updateParagraph
55                 .connect(slot(this, &FormParagraph::changedParagraph));
56         FormBaseBD::connect();
57 }
58
59
60 void FormParagraph::disconnect()
61 {
62         cp_.disconnect();
63         FormBaseBD::disconnect();
64 }
65
66
67 Paragraph const * FormParagraph::getCurrentParagraph() const
68 {
69         return lv_->view()->getLyXText()->cursor.par();
70 }
71
72
73 void FormParagraph::changedParagraph()
74 {
75         /// Record the paragraph
76         Paragraph const * const p = getCurrentParagraph();
77         if (p == 0 || p == par_)
78                 return;
79 #ifdef WITH_WARNINGS
80 #warning Please someone of you GUII people have a look at this!
81 #endif
82         // shouldn't we chage the par_ pointer too?
83         // anyway for me the below function does just nothing!
84         // (Jug 20020108)
85
86         // For now don't bother checking if the params are different,
87         // just activate the Apply button
88         bc().valid();
89 }
90
91
92 void FormParagraph::redraw()
93 {
94         if( form() && form()->visible )
95                 fl_redraw_form( form() );
96 }
97
98
99 FL_FORM * FormParagraph::form() const
100 {
101     if (dialog_.get()) return dialog_->form;
102     return 0;
103 }
104
105
106 void FormParagraph::build()
107 {
108     // the tabbed folder
109     dialog_.reset(build_paragraph());
110
111     fl_addto_choice(dialog_->choice_space_above,
112                     _(" None | Defskip | Smallskip "
113                       "| Medskip | Bigskip | VFill | Length "));
114     fl_addto_choice(dialog_->choice_space_below,
115                     _(" None | Defskip | Smallskip "
116                       "| Medskip | Bigskip | VFill | Length ")); 
117
118     fl_addto_choice(dialog_->choice_linespacing,
119                     _(" Default | Single | OneHalf | Double | Other "));
120  
121     fl_set_input_return(dialog_->input_space_above, FL_RETURN_CHANGED);
122     fl_set_input_return(dialog_->input_space_below, FL_RETURN_CHANGED);
123     fl_set_input_return(dialog_->input_labelwidth, FL_RETURN_CHANGED);
124     fl_set_input_return(dialog_->input_linespacing, FL_RETURN_CHANGED);
125     fl_set_input_filter(dialog_->input_linespacing, fl_unsigned_float_filter);
126
127     // Create the contents of the unit choices
128     // Don't include the "%" terms...
129     std::vector<string> units_vec = getLatexUnits();
130     for (std::vector<string>::iterator it = units_vec.begin();
131        it != units_vec.end(); ++it) {
132        if (contains(*it, "%"))
133                it = units_vec.erase(it, it+1) - 1;
134     }
135     string units = getStringFromVector(units_vec, "|");
136
137     fl_addto_choice(dialog_->choice_value_space_above,  units.c_str());
138     fl_addto_choice(dialog_->choice_value_space_below, units.c_str());
139
140     // Manage the ok, apply, restore and cancel/close buttons
141     bc_.setOK(dialog_->button_ok);
142     bc_.setApply(dialog_->button_apply);
143     bc_.setCancel(dialog_->button_cancel);
144     bc_.setRestore(dialog_->button_restore);
145
146     bc_.addReadOnly (dialog_->group_radio_alignment);
147     // bc_.addReadOnly (dialog_->radio_align_right);
148     // bc_.addReadOnly (dialog_->radio_align_left);
149     // bc_.addReadOnly (dialog_->radio_align_block);
150     // bc_.addReadOnly (dialog_->radio_align_center);
151     bc_.addReadOnly (dialog_->check_lines_top);
152     bc_.addReadOnly (dialog_->check_lines_bottom);
153     bc_.addReadOnly (dialog_->check_pagebreaks_top);
154     bc_.addReadOnly (dialog_->check_pagebreaks_bottom);
155     bc_.addReadOnly (dialog_->choice_space_above);
156     bc_.addReadOnly (dialog_->input_space_above);
157     bc_.addReadOnly (dialog_->check_space_above);
158     bc_.addReadOnly (dialog_->choice_space_below);
159     bc_.addReadOnly (dialog_->input_space_below);
160     bc_.addReadOnly (dialog_->check_space_below);
161     bc_.addReadOnly (dialog_->choice_linespacing);
162     bc_.addReadOnly (dialog_->input_linespacing); 
163     bc_.addReadOnly (dialog_->check_noindent);
164     bc_.addReadOnly (dialog_->input_labelwidth);
165 }
166
167
168 void FormParagraph::apply()
169 {
170     if (!lv_->view()->available() || !dialog_.get())
171         return;
172
173     VSpace space_top, space_bottom;
174     LyXAlignment align;
175     string labelwidthstring;
176     bool noindent;
177
178     // If a vspace kind is "Length" but there's no text in
179     // the input field, reset the kind to "None". 
180     if ((fl_get_choice (dialog_->choice_space_above) == 7) &&
181         !*(fl_get_input (dialog_->input_space_above)))
182     {
183         fl_set_choice (dialog_->choice_space_above, 1);
184     }
185     if ((fl_get_choice (dialog_->choice_space_below) == 7) &&
186         !*(fl_get_input (dialog_->input_space_below)))
187     {
188         fl_set_choice (dialog_->choice_space_below, 1);
189     }
190    
191     bool line_top = fl_get_button(dialog_->check_lines_top);
192     bool line_bottom = fl_get_button(dialog_->check_lines_bottom);
193     bool pagebreak_top = fl_get_button(dialog_->check_pagebreaks_top);
194     bool pagebreak_bottom = fl_get_button(dialog_->check_pagebreaks_bottom);
195     
196     switch (fl_get_choice (dialog_->choice_space_above)) {
197     case 1:
198         space_top = VSpace(VSpace::NONE);
199         break;
200     case 2:
201         space_top = VSpace(VSpace::DEFSKIP);
202         break;
203     case 3:
204         space_top = VSpace(VSpace::SMALLSKIP);
205         break;
206     case 4:
207         space_top = VSpace(VSpace::MEDSKIP);
208         break;
209     case 5:
210         space_top = VSpace(VSpace::BIGSKIP);
211         break;
212     case 6:
213         space_top = VSpace(VSpace::VFILL);
214         break;
215     case 7:
216     {
217             string const length =
218                     getLengthFromWidgets(dialog_->input_space_above,
219                                          dialog_->choice_value_space_above);
220         space_top =
221                 VSpace(LyXGlueLength(length));
222         break;
223     }
224     }
225
226     if (fl_get_button (dialog_->check_space_above))
227         space_top.setKeep (true);
228     switch (fl_get_choice (dialog_->choice_space_below)) {
229     case 1:
230         space_bottom = VSpace(VSpace::NONE);
231         break;
232     case 2:
233         space_bottom = VSpace(VSpace::DEFSKIP);
234         break;
235     case 3:
236         space_bottom = VSpace(VSpace::SMALLSKIP);
237         break;
238     case 4:
239         space_bottom = VSpace(VSpace::MEDSKIP);
240         break;
241     case 5:
242         space_bottom = VSpace(VSpace::BIGSKIP);
243         break;
244     case 6:
245         space_bottom = VSpace(VSpace::VFILL);
246         break;
247     case 7:
248         string const length =
249                 getLengthFromWidgets(dialog_->input_space_below,
250                                      dialog_->choice_value_space_below);
251         space_bottom = VSpace(LyXGlueLength(length));
252         break;
253     }
254     if (fl_get_button (dialog_->check_space_below))
255         space_bottom.setKeep (true);
256
257     if (fl_get_button(dialog_->radio_align_left))
258         align = LYX_ALIGN_LEFT;
259     else if (fl_get_button(dialog_->radio_align_right))
260         align = LYX_ALIGN_RIGHT;
261     else if (fl_get_button(dialog_->radio_align_center))
262         align = LYX_ALIGN_CENTER;
263     else 
264         align = LYX_ALIGN_BLOCK;
265    
266     labelwidthstring = fl_get_input(dialog_->input_labelwidth);
267     noindent = fl_get_button(dialog_->check_noindent);
268     Spacing::Space linespacing = Spacing::Default;
269     string other_linespacing;
270     switch (fl_get_choice(dialog_->choice_linespacing)) {
271         case 1: linespacing = Spacing::Default; break;
272         case 2: linespacing = Spacing::Single; break;
273         case 3: linespacing = Spacing::Onehalf; break;
274         case 4: linespacing = Spacing::Double; break;
275         case 5:
276             linespacing = Spacing::Other;
277             other_linespacing = fl_get_input(dialog_->input_linespacing);
278             break;
279     }
280
281     Spacing const spacing(linespacing, other_linespacing);
282     LyXText * text(lv_->view()->getLyXText());
283     text->setParagraph(lv_->view(), line_top, line_bottom, pagebreak_top,
284                        pagebreak_bottom, space_top, space_bottom, spacing,
285                        align, labelwidthstring, noindent);
286
287
288     // Actually apply these settings
289     lv_->view()->update(text, 
290                         BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
291     lv_->buffer()->markDirty();
292     setMinibuffer(lv_, _("Paragraph layout set"));
293 }
294
295
296 void FormParagraph::update()
297 {
298     if (!dialog_.get())
299         return;
300
301     // Do this first; some objects may be de/activated subsequently.
302     bc_.readOnly(lv_->buffer()->isReadonly());
303
304     Buffer * buf = lv_->view()->buffer();
305
306     /// Record the paragraph
307     par_ = getCurrentParagraph();
308
309     fl_set_input(dialog_->input_labelwidth,
310                  par_->getLabelWidthString().c_str());
311     setEnabled(dialog_->input_labelwidth,
312                (par_->getLabelWidthString() != _("Senseless with this layout!")));
313
314     fl_set_button(dialog_->radio_align_right, 0);
315     fl_set_button(dialog_->radio_align_left, 0);
316     fl_set_button(dialog_->radio_align_center, 0);
317     fl_set_button(dialog_->radio_align_block, 0);
318
319     int align = par_->getAlign();
320     if (align == LYX_ALIGN_LAYOUT)
321         align = textclasslist.Style(buf->params.textclass,
322                                     par_->getLayout()).align;
323
324     switch (align) {
325     case LYX_ALIGN_RIGHT:
326         fl_set_button(dialog_->radio_align_right, 1);
327         break;
328     case LYX_ALIGN_LEFT:
329         fl_set_button(dialog_->radio_align_left, 1);
330         break;
331     case LYX_ALIGN_CENTER:
332         fl_set_button(dialog_->radio_align_center, 1);
333         break;
334     default:
335         fl_set_button(dialog_->radio_align_block, 1);
336         break;
337     }
338
339     LyXAlignment alignpos =
340             textclasslist.Style(buf->params.textclass,
341                                 par_->getLayout()).alignpossible;
342
343     setEnabled(dialog_->radio_align_block,  bool(alignpos & LYX_ALIGN_BLOCK));
344     setEnabled(dialog_->radio_align_center, bool(alignpos & LYX_ALIGN_CENTER));
345     setEnabled(dialog_->radio_align_left,   bool(alignpos & LYX_ALIGN_LEFT));
346     setEnabled(dialog_->radio_align_right,  bool(alignpos & LYX_ALIGN_RIGHT));
347     
348     // no inset-text-owned paragraph may have pagebreaks
349     setEnabled(dialog_->check_pagebreaks_top, !par_->inInset());
350     setEnabled(dialog_->check_pagebreaks_bottom, !par_->inInset());
351
352     fl_set_button(dialog_->check_lines_top,
353                   par_->params().lineTop());
354     fl_set_button(dialog_->check_lines_bottom,
355                   par_->params().lineBottom());
356     fl_set_button(dialog_->check_pagebreaks_top,
357                   par_->params().pagebreakTop());
358     fl_set_button(dialog_->check_pagebreaks_bottom,
359                   par_->params().pagebreakBottom());
360     fl_set_button(dialog_->check_noindent,
361                   par_->params().noindent());
362
363     int linespacing;
364     Spacing const space = par_->params().spacing();
365
366     switch (space.getSpace()) {
367         default: linespacing = 1; break;
368         case Spacing::Single: linespacing = 2; break;
369         case Spacing::Onehalf: linespacing = 3; break;
370         case Spacing::Double: linespacing = 4; break;
371         case Spacing::Other: linespacing = 5; break;
372     }
373  
374     fl_set_choice(dialog_->choice_linespacing, linespacing);
375     if (space.getSpace() == Spacing::Other) {
376         string const sp = tostr(space.getValue());
377         fl_set_input(dialog_->input_linespacing, sp.c_str());
378         setEnabled(dialog_->input_linespacing, true);
379     } else {
380         fl_set_input(dialog_->input_linespacing, "");
381         setEnabled(dialog_->input_linespacing, false);
382     }
383
384     fl_set_input (dialog_->input_space_above, "");
385
386     setEnabled(dialog_->input_space_above, false);
387     setEnabled(dialog_->choice_value_space_above, false);
388     switch (par_->params().spaceTop().kind()) {
389     case VSpace::NONE:
390         fl_set_choice (dialog_->choice_space_above, 1);
391         break;
392     case VSpace::DEFSKIP:
393         fl_set_choice (dialog_->choice_space_above, 2);
394         break;
395     case VSpace::SMALLSKIP:
396         fl_set_choice (dialog_->choice_space_above, 3);
397         break;
398     case VSpace::MEDSKIP:
399         fl_set_choice (dialog_->choice_space_above, 4);
400         break;
401     case VSpace::BIGSKIP:
402         fl_set_choice (dialog_->choice_space_above, 5);
403         break;
404     case VSpace::VFILL:
405         fl_set_choice (dialog_->choice_space_above, 6);
406         break;
407     case VSpace::LENGTH:
408     {
409         fl_set_choice (dialog_->choice_space_above, 7);
410         setEnabled(dialog_->input_space_above, true);
411         setEnabled(dialog_->choice_value_space_above, true);
412         bool const metric = lyxrc.default_papersize > 3;
413         string const default_unit = metric ? "cm" : "in";
414         string const length = par_->params().spaceTop().length().asString();
415         //check if there's a stretch or shrink factor
416         if (!isValidLength(length) && !isStrDbl(length))
417                 fl_set_input(dialog_->input_space_above, length.c_str());
418         else {
419                 updateWidgetsFromLengthString(dialog_->input_space_above,
420                                               dialog_->choice_value_space_above,
421                                               length, default_unit);
422         }
423         break;
424     }
425     }
426     
427     fl_set_button (dialog_->check_space_above,
428            par_->params().spaceTop().keep());
429     fl_set_input (dialog_->input_space_below, "");
430
431     setEnabled(dialog_->input_space_below, false);
432     setEnabled(dialog_->choice_value_space_below, false);
433     switch (par_->params().spaceBottom().kind()) {
434     case VSpace::NONE:
435         fl_set_choice (dialog_->choice_space_below, 1);
436         break;
437     case VSpace::DEFSKIP:
438         fl_set_choice (dialog_->choice_space_below, 2);
439         break;
440     case VSpace::SMALLSKIP:
441         fl_set_choice (dialog_->choice_space_below, 3);
442         break;
443     case VSpace::MEDSKIP:
444         fl_set_choice (dialog_->choice_space_below, 4);
445         break;
446     case VSpace::BIGSKIP:
447         fl_set_choice (dialog_->choice_space_below, 5);
448         break;
449     case VSpace::VFILL:
450         fl_set_choice (dialog_->choice_space_below, 6);
451         break;
452     case VSpace::LENGTH:
453     {
454         fl_set_choice (dialog_->choice_space_below, 7);
455         setEnabled(dialog_->input_space_below, true);
456         setEnabled(dialog_->choice_value_space_below, true);
457         bool const metric = lyxrc.default_papersize > 3;
458         string const default_unit = metric ? "cm" : "in";
459         string const length =
460                 par_->params().spaceBottom().length().asString();
461         //check if there's a stretch or shrink factor
462         if (!isValidLength(length) && !isStrDbl(length))
463                 fl_set_input(dialog_->input_space_below, length.c_str());
464         else {
465                 updateWidgetsFromLengthString(dialog_->input_space_below,
466                                               dialog_->choice_value_space_below,
467                                               length, default_unit);
468         }
469         break;
470     }
471     }
472
473     fl_set_button(dialog_->check_space_below,
474                   par_->params().spaceBottom().keep());
475     fl_set_button(dialog_->check_noindent,
476                   par_->params().noindent());
477 }
478
479
480 bool FormParagraph::input(FL_OBJECT * ob, long)
481 {
482     bool valid = true; 
483
484     fl_hide_object(dialog_->text_warning);
485
486     // First check the buttons which are exclusive and you have to
487     // check only the actuall de/activated button.
488     //
489     // "Synchronize" the choices and input fields, making it
490     // impossible to commit senseless data.
491
492     if (ob == dialog_->choice_space_above) {
493         if (fl_get_choice (dialog_->choice_space_above) != 7) {
494             fl_set_input (dialog_->input_space_above, "");
495             setEnabled (dialog_->input_space_above, false);
496             setEnabled (dialog_->choice_value_space_above, false);
497         } else {
498             setEnabled (dialog_->input_space_above, !lv_->buffer()->isReadonly());
499             setEnabled (dialog_->choice_value_space_above, !lv_->buffer()->isReadonly());
500             bool const metric = lyxrc.default_papersize > 3;
501             int const default_unit = metric ? 8 : 9;
502             if (strip(fl_get_input(dialog_->input_space_above)).empty())
503                 fl_set_choice(dialog_->choice_value_space_above,
504                               default_unit);
505         }
506     }
507     if (ob == dialog_->choice_space_below) {
508         if (fl_get_choice (dialog_->choice_space_below) != 7) {
509             fl_set_input (dialog_->input_space_below, "");
510             setEnabled (dialog_->input_space_below, false);
511             setEnabled (dialog_->choice_value_space_below, false);
512         } else {
513             setEnabled (dialog_->input_space_below, !lv_->buffer()->isReadonly());
514             setEnabled (dialog_->choice_value_space_below, !lv_->buffer()->isReadonly());
515             bool const metric = lyxrc.default_papersize > 3;
516             int const default_unit = metric ? 8 : 9;
517             if (strip(fl_get_input(dialog_->input_space_below)).empty())
518                     fl_set_choice(dialog_->choice_value_space_below,
519                                   default_unit);
520         }
521     }
522  
523     //
524     // warnings if input is senseless
525     //
526     string input = fl_get_input (dialog_->input_space_above);
527     bool invalid = false;
528
529     if (fl_get_choice(dialog_->choice_space_above)==7)
530         invalid = !input.empty() && !isValidGlueLength(input) && !isStrDbl(input);
531
532     input = fl_get_input (dialog_->input_space_below);
533
534     if (fl_get_choice(dialog_->choice_space_below)==7)
535         invalid = invalid
536                 || (!input.empty() && !isValidGlueLength(input) && !isStrDbl(input));
537
538     if (ob == dialog_->input_space_above || ob == dialog_->input_space_below) {
539         if (invalid) {
540             fl_set_object_label(dialog_->text_warning,
541                 _("Warning: Invalid Length (valid example: 10mm)"));
542             fl_show_object(dialog_->text_warning);
543             return false;
544         } else {
545             fl_hide_object(dialog_->text_warning);
546             return true;
547         }
548     }
549
550     if (fl_get_choice (dialog_->choice_linespacing) == 5)
551         setEnabled (dialog_->input_linespacing, true);
552     else {
553         setEnabled (dialog_->input_linespacing, false);
554         fl_set_input (dialog_->input_linespacing, "");
555     }
556
557     double spacing(strToDbl(fl_get_input(dialog_->input_linespacing)));
558
559     if (fl_get_choice (dialog_->choice_linespacing) == 5
560         && int(spacing) == 0)
561         valid = false;
562
563     return valid;
564 }