]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiParagraph.cpp
do what the FIXME suggested
[lyx.git] / src / frontends / qt4 / GuiParagraph.cpp
1 /**
2  * \file GuiParagraph.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Edwin Leuven
7  * \author Richard Heck
8  * \author Abdelrazak Younes
9  * \author Angus Leeming
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "GuiParagraph.h"
17
18 #include "qt_helpers.h"
19
20 #include "Buffer.h"
21 #include "BufferParams.h"
22 #include "BufferView.h"
23 #include "Cursor.h"
24 #include "FuncRequest.h"
25 #include "GuiView.h"
26 #include "Lexer.h"
27 #include "Paragraph.h"
28 #include "ParagraphParameters.h"
29 #include "Spacing.h"
30
31 #include "support/debug.h"
32 #include "support/gettext.h"
33
34 #include <QCheckBox>
35 #include <QLineEdit>
36 #include <QPushButton>
37
38 #include <sstream>
39
40 using namespace std;
41
42 namespace lyx {
43 namespace frontend {
44
45 GuiParagraph::GuiParagraph(GuiView & lv)
46         : DialogView(lv, "paragraph", qt_("Paragraph Settings"))
47 {
48         setupUi(this);
49
50         connect(alignDefaultRB, SIGNAL(clicked()), this, SLOT(changed()));
51         connect(alignJustRB, SIGNAL(clicked()), this, SLOT(changed()));
52         connect(alignLeftRB, SIGNAL(clicked()), this, SLOT(changed()));
53         connect(alignRightRB, SIGNAL(clicked()), this, SLOT(changed()));
54         connect(alignCenterRB, SIGNAL(clicked()), this, SLOT(changed()));
55         connect(linespacing, SIGNAL(activated(int)), this, SLOT(changed()));
56         connect(linespacingValue, SIGNAL(textChanged(QString)),
57                 this, SLOT(changed()));
58         connect(indentCB, SIGNAL(clicked()), this, SLOT(changed()));
59         connect(labelWidth, SIGNAL(textChanged(QString)),
60                 this, SLOT(changed()));
61
62 #ifdef Q_WS_MACX
63         // On Mac it's common to have tool windows which are always in the
64         // foreground and are hidden when the main window is not focused.
65         setWindowFlags(Qt::Tool);
66         synchronizedViewCB->setChecked(true);
67 #else
68         synchronizedViewCB->setChecked(false);
69 #endif
70
71         on_synchronizedViewCB_toggled();
72         linespacingValue->setValidator(new QDoubleValidator(linespacingValue));
73
74         labelWidth->setWhatsThis( qt_(
75                 "As described in the User Guide, the width of"
76                 " this text determines the width of the label part"
77                 " of each item in environments like List and"
78                 " Description.\n"
79                 "\n"
80                 " Normally, you won't need to set this,"
81                 " since the largest label width of all the"
82                 " items is used."
83         ));
84
85         radioMap[LYX_ALIGN_LAYOUT] = alignDefaultRB;
86         radioMap[LYX_ALIGN_BLOCK]  = alignJustRB;
87         radioMap[LYX_ALIGN_LEFT]   = alignLeftRB;
88         radioMap[LYX_ALIGN_RIGHT]  = alignRightRB;
89         radioMap[LYX_ALIGN_CENTER] = alignCenterRB;
90
91         labelMap[LYX_ALIGN_BLOCK]  = _("Justified");
92         labelMap[LYX_ALIGN_LEFT]   = _("Left");
93         labelMap[LYX_ALIGN_RIGHT]  = _("Right");
94         labelMap[LYX_ALIGN_CENTER] = _("Center");
95
96         const_cast<QString &>(alignDefaultLabel) = alignDefaultRB->text();
97 }
98
99
100 void GuiParagraph::on_linespacing_activated(int index)
101 {
102         linespacingValue->setEnabled(index == 4);
103 }
104
105
106 void GuiParagraph::checkAlignmentRadioButtons()
107 {
108         RadioMap::iterator it = radioMap.begin();
109         for (; it != radioMap.end(); ++it) {
110                 LyXAlignment const align = it->first;
111                 it->second->setEnabled(align & alignPossible());
112         }
113         if (haveMultiParSelection())
114                 alignDefaultRB->setText(alignDefaultLabel);
115         else
116                 alignDefaultRB->setText(alignDefaultLabel + " ("
117                         + toqstr(labelMap[alignDefault()]) + ")");
118 }
119
120
121 void GuiParagraph::alignmentToRadioButtons(LyXAlignment align)
122 {
123         RadioMap::const_iterator it = radioMap.begin();
124         for (;it != radioMap.end(); ++it) {
125                 it->second->blockSignals(true);
126                 it->second->setChecked(align == it->first);
127                 it->second->blockSignals(false);
128         }
129 }
130
131
132 LyXAlignment GuiParagraph::getAlignmentFromDialog()
133 {
134         LyXAlignment alignment = LYX_ALIGN_NONE;
135         RadioMap::const_iterator it = radioMap.begin();
136         for (; it != radioMap.end(); ++it) {
137                 if (it->second->isChecked()) {
138                         alignment = it->first;
139                         break;
140                 }
141         }
142         return alignment;
143 }
144
145
146 void GuiParagraph::on_synchronizedViewCB_toggled()
147 {
148         bool in_sync = synchronizedViewCB->isChecked();
149         restorePB->setEnabled(!in_sync);
150         applyPB->setEnabled(!in_sync);
151 }
152
153
154 void GuiParagraph::changed()
155 {
156         if (synchronizedViewCB->isChecked())
157                 on_applyPB_clicked();
158 }
159
160
161 void GuiParagraph::on_applyPB_clicked()
162 {
163         ParagraphParameters & pp = params();
164
165         pp.align(getAlignmentFromDialog());
166
167         // get spacing
168         Spacing::Space ls = Spacing::Default;
169         string other;
170         switch (linespacing->currentIndex()) {
171         case 0:
172                 ls = Spacing::Default;
173                 break;
174         case 1:
175                 ls = Spacing::Single;
176                 break;
177         case 2:
178                 ls = Spacing::Onehalf;
179                 break;
180         case 3:
181                 ls = Spacing::Double;
182                 break;
183         case 4:
184                 ls = Spacing::Other;
185                 other = fromqstr(linespacingValue->text());
186                 break;
187         }
188
189         Spacing const spacing(ls, other);
190         pp.spacing(spacing);
191
192         // label width
193         pp.labelWidthString(qstring_to_ucs4(labelWidth->text()));
194         // indendation
195         pp.noindent(!indentCB->isChecked());
196
197         dispatchParams();
198 }
199
200
201 void GuiParagraph::on_restorePB_clicked()
202 {
203         updateView();
204 }
205
206
207 void GuiParagraph::updateView()
208 {
209         on_synchronizedViewCB_toggled();
210
211         ParagraphParameters const & pp = params();
212
213         // label width
214         docstring const & labelwidth = pp.labelWidthString();
215         // FIXME We should not compare translated strings
216         if (labelwidth != _("Senseless with this layout!")) {
217                 labelwidthGB->setEnabled(true);
218                 labelWidth->setText(toqstr(labelwidth));
219         } else {
220                 labelwidthGB->setEnabled(false);
221                 labelWidth->setText("");
222         }
223
224         // alignment
225         checkAlignmentRadioButtons();
226         alignmentToRadioButtons(pp.align());
227
228         //indentation
229         bool const canindent = canIndent();
230         indentCB->setEnabled(canindent);
231         indentCB->setChecked(canindent && !pp.noindent());
232
233         // linespacing
234         int ls;
235         Spacing const & space = pp.spacing();
236         switch (space.getSpace()) {
237         case Spacing::Single:
238                 ls = 1;
239                 break;
240         case Spacing::Onehalf:
241                 ls = 2;
242                 break;
243         case Spacing::Double:
244                 ls = 3;
245                 break;
246         case Spacing::Other:
247                 ls = 4;
248                 break;
249         default:
250                 ls = 0;
251                 break;
252         }
253         linespacing->setCurrentIndex(ls);
254         if (space.getSpace() == Spacing::Other) {
255                 linespacingValue->setText(toqstr(space.getValueAsString()));
256                 linespacingValue->setEnabled(true);
257         } else {
258                 linespacingValue->setText(QString());
259                 linespacingValue->setEnabled(false);
260         }
261 }
262
263
264 void GuiParagraph::enableView(bool enable)
265 {
266         indentCB->setEnabled(enable);
267         linespacing->setEnabled(enable);
268         labelWidth->setEnabled(enable);
269         synchronizedViewCB->setEnabled(enable);
270         applyPB->setEnabled(enable);
271         restorePB->setEnabled(enable);
272         if (!enable)
273                 synchronizedViewCB->setChecked(true);
274         RadioMap::const_iterator it = radioMap.begin();
275         for (; it != radioMap.end(); ++it)
276                 it->second->setEnabled(enable);
277 }
278
279
280 ParagraphParameters & GuiParagraph::params()
281 {
282         if (haveMultiParSelection()) {
283                 multiparsel_ = ParagraphParameters();
284                 // FIXME: It would be nice to initialise the parameters that
285                 // are common to all paragraphs.
286                 return multiparsel_;
287         }
288
289         return bufferview()->cursor().innerParagraph().params();
290 }
291
292
293 ParagraphParameters const & GuiParagraph::params() const
294 {
295         return bufferview()->cursor().innerParagraph().params();
296 }
297
298
299 void GuiParagraph::dispatchParams()
300 {
301         if (haveMultiParSelection()) {
302                 ostringstream data;
303                 multiparsel_.write(data);
304                 FuncRequest const fr(getLfun(), data.str());
305                 dispatch(fr);
306                 return;
307         }
308
309         bufferview()->updateMetrics();
310         bufferview()->buffer().changed();
311 }
312
313
314 bool GuiParagraph::haveMultiParSelection()
315 {
316         Cursor cur = bufferview()->cursor();
317         return cur.selection() && cur.selBegin().pit() != cur.selEnd().pit();
318 }
319
320         
321 bool GuiParagraph::canIndent() const
322 {
323         return buffer().params().paragraph_separation ==
324                 BufferParams::PARSEP_INDENT;
325 }
326
327
328 LyXAlignment GuiParagraph::alignPossible() const
329 {
330         return bufferview()->cursor().innerParagraph().layout()->alignpossible;
331 }
332
333
334 LyXAlignment GuiParagraph::alignDefault() const
335 {
336         return bufferview()->cursor().innerParagraph().layout()->align;
337 }
338
339
340 Dialog * createGuiParagraph(GuiView & lv)
341 {
342         return new GuiParagraph(lv);
343 }
344
345
346 } // namespace frontend
347 } // namespace lyx
348
349 #include "GuiParagraph_moc.cpp"