]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiParagraph.cpp
* For gcc to know about QStandardItemModel < QAbstractItemModel we need this header.
[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         closePB->setText(qt_("&Cancel"));
68 #else
69         synchronizedViewCB->setChecked(false);
70 #endif
71
72         on_synchronizedViewCB_toggled();
73         linespacingValue->setValidator(new QDoubleValidator(linespacingValue));
74
75         labelWidth->setWhatsThis(qt_(
76                 "As described in the User Guide, the width of"
77                 " this text determines the width of the label part"
78                 " of each item in environments like List and"
79                 " Description.\n"
80                 "\n"
81                 " Normally, you won't need to set this,"
82                 " since the largest label width of all the"
83                 " items is used."
84         ));
85
86         radioMap_[LYX_ALIGN_LAYOUT] = alignDefaultRB;
87         radioMap_[LYX_ALIGN_BLOCK]  = alignJustRB;
88         radioMap_[LYX_ALIGN_LEFT]   = alignLeftRB;
89         radioMap_[LYX_ALIGN_RIGHT]  = alignRightRB;
90         radioMap_[LYX_ALIGN_CENTER] = alignCenterRB;
91
92         alignDefaultLabel_ = alignDefaultRB->text();
93 }
94
95
96 void GuiParagraph::on_linespacing_activated(int index)
97 {
98         linespacingValue->setEnabled(index == 4);
99 }
100
101
102 void GuiParagraph::checkAlignmentRadioButtons()
103 {
104         static std::map<LyXAlignment, QString> labelMap_;
105         if (labelMap_.empty()) {
106                 labelMap_[LYX_ALIGN_BLOCK]  = qt_("Justified");
107                 labelMap_[LYX_ALIGN_LEFT]   = qt_("Left");
108                 labelMap_[LYX_ALIGN_RIGHT]  = qt_("Right");
109                 labelMap_[LYX_ALIGN_CENTER] = qt_("Center");
110         }
111
112         RadioMap::iterator it = radioMap_.begin();
113         for (; it != radioMap_.end(); ++it) {
114                 LyXAlignment const align = it->first;
115                 it->second->setEnabled(align & alignPossible());
116         }
117         if (haveMultiParSelection())
118                 alignDefaultRB->setText(alignDefaultLabel_);
119         else
120                 alignDefaultRB->setText(alignDefaultLabel_ + " ("
121                         + labelMap_[alignDefault()] + ")");
122 }
123
124
125 void GuiParagraph::alignmentToRadioButtons(LyXAlignment align)
126 {
127         RadioMap::const_iterator it = radioMap_.begin();
128         for (;it != radioMap_.end(); ++it) {
129                 it->second->blockSignals(true);
130                 it->second->setChecked(align == it->first);
131                 it->second->blockSignals(false);
132         }
133 }
134
135
136 LyXAlignment GuiParagraph::getAlignmentFromDialog()
137 {
138         LyXAlignment alignment = LYX_ALIGN_NONE;
139         RadioMap::const_iterator it = radioMap_.begin();
140         for (; it != radioMap_.end(); ++it) {
141                 if (it->second->isChecked()) {
142                         alignment = it->first;
143                         break;
144                 }
145         }
146         return alignment;
147 }
148
149
150 void GuiParagraph::on_synchronizedViewCB_toggled()
151 {
152         bool in_sync = synchronizedViewCB->isChecked();
153         restorePB->setEnabled(!in_sync);
154         applyPB->setEnabled(!in_sync);
155         okPB->setEnabled(!in_sync);
156         if (!in_sync)
157                 closePB->setText(qt_("&Cancel"));
158         else
159                 closePB->setText(qt_("&Close"));
160 }
161
162
163 void GuiParagraph::changed()
164 {
165         if (synchronizedViewCB->isChecked())
166                 on_applyPB_clicked();
167 }
168
169
170 void GuiParagraph::on_applyPB_clicked()
171 {
172         applyView();
173 }
174
175
176 void GuiParagraph::on_okPB_clicked()
177 {
178         applyView();
179         hide();
180 }
181
182
183 void GuiParagraph::on_closePB_clicked()
184 {
185         hide();
186 }
187
188
189 void GuiParagraph::on_restorePB_clicked()
190 {
191         updateView();
192 }
193
194
195 void GuiParagraph::applyView()
196 {
197         ParagraphParameters & pp = params();
198
199         pp.align(getAlignmentFromDialog());
200
201         // get spacing
202         Spacing::Space ls = Spacing::Default;
203         string other;
204         switch (linespacing->currentIndex()) {
205         case 0:
206                 ls = Spacing::Default;
207                 break;
208         case 1:
209                 ls = Spacing::Single;
210                 break;
211         case 2:
212                 ls = Spacing::Onehalf;
213                 break;
214         case 3:
215                 ls = Spacing::Double;
216                 break;
217         case 4:
218                 ls = Spacing::Other;
219                 other = fromqstr(linespacingValue->text());
220                 break;
221         }
222
223         Spacing const spacing(ls, other);
224         pp.spacing(spacing);
225
226         // label width
227         pp.labelWidthString(qstring_to_ucs4(labelWidth->text()));
228         // indendation
229         pp.noindent(!indentCB->isChecked());
230
231         dispatchParams();
232 }
233
234
235 void GuiParagraph::updateView()
236 {
237         on_synchronizedViewCB_toggled();
238
239         ParagraphParameters const & pp = params();
240
241         // label width
242         docstring const & labelwidth = pp.labelWidthString();
243         // FIXME We should not compare translated strings
244         if (labelwidth != _("Senseless with this layout!")) {
245                 labelwidthGB->setEnabled(true);
246                 labelWidth->setText(toqstr(labelwidth));
247         } else {
248                 labelwidthGB->setEnabled(false);
249                 labelWidth->setText(QString());
250         }
251
252         // alignment
253         checkAlignmentRadioButtons();
254         alignmentToRadioButtons(pp.align());
255
256         //indentation
257         bool const canindent = canIndent();
258         indentCB->setEnabled(canindent);
259         indentCB->setChecked(canindent && !pp.noindent());
260
261         // linespacing
262         int ls;
263         Spacing const & space = pp.spacing();
264         switch (space.getSpace()) {
265         case Spacing::Single:
266                 ls = 1;
267                 break;
268         case Spacing::Onehalf:
269                 ls = 2;
270                 break;
271         case Spacing::Double:
272                 ls = 3;
273                 break;
274         case Spacing::Other:
275                 ls = 4;
276                 break;
277         default:
278                 ls = 0;
279                 break;
280         }
281         linespacing->setCurrentIndex(ls);
282         if (space.getSpace() == Spacing::Other) {
283                 linespacingValue->setText(toqstr(space.getValueAsString()));
284                 linespacingValue->setEnabled(true);
285         } else {
286                 linespacingValue->setText(QString());
287                 linespacingValue->setEnabled(false);
288         }
289 }
290
291
292 void GuiParagraph::enableView(bool enable)
293 {
294         indentCB->setEnabled(enable);
295         linespacing->setEnabled(enable);
296         labelWidth->setEnabled(enable);
297         synchronizedViewCB->setEnabled(enable);
298         applyPB->setEnabled(enable);
299         restorePB->setEnabled(enable);
300         if (!enable)
301                 synchronizedViewCB->setChecked(true);
302         RadioMap::const_iterator it = radioMap_.begin();
303         for (; it != radioMap_.end(); ++it)
304                 it->second->setEnabled(enable);
305 }
306
307
308 ParagraphParameters & GuiParagraph::params()
309 {
310         if (haveMultiParSelection()) {
311                 multiparsel_ = ParagraphParameters();
312                 // FIXME: It would be nice to initialise the parameters that
313                 // are common to all paragraphs.
314                 return multiparsel_;
315         }
316
317         return bufferview()->cursor().innerParagraph().params();
318 }
319
320
321 ParagraphParameters const & GuiParagraph::params() const
322 {
323         return bufferview()->cursor().innerParagraph().params();
324 }
325
326
327 void GuiParagraph::dispatchParams()
328 {
329         if (haveMultiParSelection()) {
330                 ostringstream data;
331                 multiparsel_.write(data);
332                 FuncRequest const fr(getLfun(), data.str());
333                 dispatch(fr);
334                 return;
335         }
336
337         bufferview()->updateMetrics();
338         bufferview()->buffer().changed();
339 }
340
341
342 bool GuiParagraph::haveMultiParSelection()
343 {
344         Cursor cur = bufferview()->cursor();
345         return cur.selection() && cur.selBegin().pit() != cur.selEnd().pit();
346 }
347
348         
349 bool GuiParagraph::canIndent() const
350 {
351         return buffer().params().paragraph_separation
352                 == BufferParams::ParagraphIndentSeparation;
353 }
354
355
356 LyXAlignment GuiParagraph::alignPossible() const
357 {
358         return bufferview()->cursor().innerParagraph().layout().alignpossible;
359 }
360
361
362 LyXAlignment GuiParagraph::alignDefault() const
363 {
364         return bufferview()->cursor().innerParagraph().layout().align;
365 }
366
367
368 Dialog * createGuiParagraph(GuiView & lv)
369 {
370         return new GuiParagraph(lv);
371 }
372
373
374 } // namespace frontend
375 } // namespace lyx
376
377 #include "GuiParagraph_moc.cpp"