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