]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiParagraph.cpp
44417364121e58d8e424427a312ffedf368b5f29
[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 "Buffer.h"
19 #include "BufferParams.h"
20 #include "BufferView.h"
21 #include "Cursor.h"
22 #include "FuncRequest.h"
23 #include "GuiView.h"
24 #include "Lexer.h"
25 #include "Paragraph.h"
26 #include "ParagraphParameters.h"
27 #include "qt_helpers.h"
28 #include "Spacing.h"
29
30 #include "support/debug.h"
31 #include "support/gettext.h"
32
33 #include <QCheckBox>
34 #include <QCloseEvent>
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 (haveMulitParSelection())
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                 if (!it->second->isEnabled())
126                         continue;
127                 it->second->blockSignals(true);
128                 it->second->setChecked(align == it->first);
129                 it->second->blockSignals(false);
130         }
131 }
132
133
134 LyXAlignment GuiParagraph::getAlignmentFromDialog()
135 {
136         LyXAlignment alignment = LYX_ALIGN_NONE;
137         RadioMap::const_iterator it = radioMap.begin();
138         for (; it != radioMap.end(); ++it) {
139                 if (it->second->isChecked()) {
140                         alignment = it->first;
141                         break;
142                 }
143         }
144         return alignment;
145 }
146
147
148 void GuiParagraph::on_synchronizedViewCB_toggled()
149 {
150         bool in_sync = synchronizedViewCB->isChecked();
151         restorePB->setEnabled(!in_sync);
152         applyPB->setEnabled(!in_sync);
153 }
154
155
156 void GuiParagraph::changed()
157 {
158         if (synchronizedViewCB->isChecked())
159                 on_applyPB_clicked();
160 }
161
162
163 void GuiParagraph::on_applyPB_clicked()
164 {
165         ParagraphParameters & pp = params();
166
167         pp.align(getAlignmentFromDialog());
168
169         // get spacing
170         Spacing::Space ls = Spacing::Default;
171         string other;
172         switch (linespacing->currentIndex()) {
173         case 0:
174                 ls = Spacing::Default;
175                 break;
176         case 1:
177                 ls = Spacing::Single;
178                 break;
179         case 2:
180                 ls = Spacing::Onehalf;
181                 break;
182         case 3:
183                 ls = Spacing::Double;
184                 break;
185         case 4:
186                 ls = Spacing::Other;
187                 other = fromqstr(linespacingValue->text());
188                 break;
189         }
190
191         Spacing const spacing(ls, other);
192         pp.spacing(spacing);
193
194         // label width
195         pp.labelWidthString(qstring_to_ucs4(labelWidth->text()));
196         // indendation
197         pp.noindent(!indentCB->isChecked());
198
199         dispatchParams();
200 }
201
202
203 void GuiParagraph::on_restorePB_clicked()
204 {
205         updateView();
206 }
207
208
209 void GuiParagraph::updateView()
210 {
211         on_synchronizedViewCB_toggled();
212
213         ParagraphParameters const & pp = params();
214
215         // label width
216         docstring const & labelwidth = pp.labelWidthString();
217         // FIXME We should not compare translated strings
218         if (labelwidth != _("Senseless with this layout!")) {
219                 labelwidthGB->setEnabled(true);
220                 labelWidth->setText(toqstr(labelwidth));
221         } else {
222                 labelwidthGB->setEnabled(false);
223                 labelWidth->setText("");
224         }
225
226         // alignment
227         checkAlignmentRadioButtons();
228         alignmentToRadioButtons(pp.align());
229
230         //indentation
231         bool const canindent = canIndent();
232         indentCB->setEnabled(canindent);
233         indentCB->setChecked(canindent && !pp.noindent());
234
235         // linespacing
236         int ls;
237         Spacing const & space = pp.spacing();
238         switch (space.getSpace()) {
239         case Spacing::Single:
240                 ls = 1;
241                 break;
242         case Spacing::Onehalf:
243                 ls = 2;
244                 break;
245         case Spacing::Double:
246                 ls = 3;
247                 break;
248         case Spacing::Other:
249                 ls = 4;
250                 break;
251         default:
252                 ls = 0;
253                 break;
254         }
255         linespacing->setCurrentIndex(ls);
256         if (space.getSpace() == Spacing::Other) {
257                 linespacingValue->setText(toqstr(space.getValueAsString()));
258                 linespacingValue->setEnabled(true);
259         } else {
260                 linespacingValue->setText(QString());
261                 linespacingValue->setEnabled(false);
262         }
263 }
264
265
266 void GuiParagraph::enableView(bool enable)
267 {
268         indentCB->setEnabled(enable);
269         linespacing->setEnabled(enable);
270         labelWidth->setEnabled(enable);
271         synchronizedViewCB->setEnabled(enable);
272         applyPB->setEnabled(enable);
273         restorePB->setEnabled(enable);
274         if (!enable)
275                 synchronizedViewCB->setChecked(true);
276         RadioMap::const_iterator it = radioMap.begin();
277         for (; it != radioMap.end(); ++it)
278                 it->second->setEnabled(enable);
279 }
280
281
282 ParagraphParameters & GuiParagraph::params()
283 {
284         if (haveMulitParSelection()) {
285                 multiparsel_ = ParagraphParameters();
286                 // FIXME: It would be nice to initialise the parameters that
287                 // are common to all paragraphs.
288                 return multiparsel_;
289         }
290
291         return bufferview()->cursor().innerParagraph().params();
292 }
293
294
295 ParagraphParameters const & GuiParagraph::params() const
296 {
297         return bufferview()->cursor().innerParagraph().params();
298 }
299
300
301 void GuiParagraph::dispatchParams()
302 {
303         if (haveMulitParSelection()) {
304                 ostringstream data;
305                 multiparsel_.write(data);
306                 FuncRequest const fr(getLfun(), data.str());
307                 dispatch(fr);
308                 return;
309         }
310
311         bufferview()->updateMetrics();
312         bufferview()->buffer().changed();
313 }
314
315
316 bool GuiParagraph::haveMulitParSelection()
317 {
318         Cursor cur = bufferview()->cursor();
319         return cur.selection() && cur.selBegin().pit() != cur.selEnd().pit();
320 }
321
322         
323 bool GuiParagraph::canIndent() const
324 {
325         return buffer().params().paragraph_separation ==
326                 BufferParams::PARSEP_INDENT;
327 }
328
329
330 LyXAlignment GuiParagraph::alignPossible() const
331 {
332         return bufferview()->cursor().innerParagraph().layout()->alignpossible;
333 }
334
335
336 LyXAlignment GuiParagraph::alignDefault() const
337 {
338         return bufferview()->cursor().innerParagraph().layout()->align;
339 }
340
341
342 Dialog * createGuiParagraph(GuiView & lv)
343 {
344 #if 0
345         GuiView & guiview = static_cast<GuiView &>(lv);
346 #ifdef USE_DOCK_WIDGET
347         return new DockView<ControlParagraph, GuiParagraph>(guiview, "paragraph",
348                 Qt::TopDockWidgetArea);
349 #else
350         return new DialogView<ControlParagraph, GuiParagraph>(guiview, "paragraph");
351 #endif
352 #endif
353
354         return new GuiParagraph(lv);
355 }
356
357
358 } // namespace frontend
359 } // namespace lyx
360
361 #include "GuiParagraph_moc.cpp"