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