]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiParagraph.cpp
2eec772f1fc95769c50281e705c8270df84ee6d5
[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 <QVariant>
38
39 #include <sstream>
40
41 using namespace std;
42
43 namespace lyx {
44 namespace frontend {
45
46 GuiParagraph::GuiParagraph(GuiView & lv)
47         : DialogView(lv, "paragraph", qt_("Paragraph Settings"))
48 {
49         setupUi(this);
50
51         connect(alignDefaultRB, SIGNAL(clicked()), this, SLOT(changed()));
52         connect(alignJustRB, SIGNAL(clicked()), this, SLOT(changed()));
53         connect(alignLeftRB, SIGNAL(clicked()), this, SLOT(changed()));
54         connect(alignRightRB, SIGNAL(clicked()), this, SLOT(changed()));
55         connect(alignCenterRB, SIGNAL(clicked()), this, SLOT(changed()));
56         connect(linespacing, SIGNAL(activated(int)), this, SLOT(changed()));
57         connect(linespacingValue, SIGNAL(textChanged(QString)),
58                 this, SLOT(changed()));
59         connect(indentCB, SIGNAL(clicked()), this, SLOT(changed()));
60         connect(labelWidth, SIGNAL(textChanged(QString)),
61                 this, SLOT(changed()));
62
63 #ifdef Q_WS_MACX
64         // On Mac it's common to have tool windows which are always in the
65         // foreground and are hidden when the main window is not focused.
66         setWindowFlags(Qt::Tool);
67         synchronizedViewCB->setChecked(true);
68         closePB->setText(qt_("&Cancel"));
69 #else
70         synchronizedViewCB->setChecked(false);
71 #endif
72
73         on_synchronizedViewCB_toggled();
74         linespacingValue->setValidator(new QDoubleValidator(linespacingValue));
75
76         labelWidth->setWhatsThis(qt_(
77                 "As described in the User Guide, the width of"
78                 " this text determines the width of the label part"
79                 " of each item in environments like List and"
80                 " Description.\n"
81                 "\n"
82                 " Normally, you won't need to set this,"
83                 " since the largest label width of all the"
84                 " items is used."
85         ));
86
87         radioMap_[LYX_ALIGN_LAYOUT] = alignDefaultRB;
88         radioMap_[LYX_ALIGN_BLOCK]  = alignJustRB;
89         radioMap_[LYX_ALIGN_LEFT]   = alignLeftRB;
90         radioMap_[LYX_ALIGN_RIGHT]  = alignRightRB;
91         radioMap_[LYX_ALIGN_CENTER] = alignCenterRB;
92
93         alignDefaultLabel_ = alignDefaultRB->text();
94 }
95
96
97 void GuiParagraph::on_linespacing_activated(int index)
98 {
99         linespacingValue->setEnabled(index == 4);
100 }
101
102
103 void GuiParagraph::checkAlignmentRadioButtons()
104 {
105         static std::map<LyXAlignment, QString> labelMap_;
106         if (labelMap_.empty()) {
107                 labelMap_[LYX_ALIGN_BLOCK]  = qt_("Justified");
108                 labelMap_[LYX_ALIGN_LEFT]   = qt_("Left");
109                 labelMap_[LYX_ALIGN_RIGHT]  = qt_("Right");
110                 labelMap_[LYX_ALIGN_CENTER] = qt_("Center");
111         }
112
113         RadioMap::iterator it = radioMap_.begin();
114         for (; it != radioMap_.end(); ++it) {
115                 LyXAlignment const align = it->first;
116                 it->second->setEnabled(align & alignPossible());
117         }
118         if (haveMultiParSelection())
119                 alignDefaultRB->setText(alignDefaultLabel_);
120         else
121                 alignDefaultRB->setText(alignDefaultLabel_ + " ("
122                         + labelMap_[alignDefault()] + ")");
123 }
124
125
126 void GuiParagraph::alignmentToRadioButtons(LyXAlignment align)
127 {
128         RadioMap::const_iterator it = radioMap_.begin();
129         for (;it != radioMap_.end(); ++it) {
130                 it->second->blockSignals(true);
131                 it->second->setChecked(align == it->first);
132                 it->second->blockSignals(false);
133         }
134 }
135
136
137 LyXAlignment GuiParagraph::getAlignmentFromDialog() const
138 {
139         LyXAlignment alignment = LYX_ALIGN_NONE;
140         RadioMap::const_iterator it = radioMap_.begin();
141         for (; it != radioMap_.end(); ++it) {
142                 if (it->second->isChecked()) {
143                         alignment = it->first;
144                         break;
145                 }
146         }
147         return alignment;
148 }
149
150
151 void GuiParagraph::on_synchronizedViewCB_toggled()
152 {
153         bool in_sync = synchronizedViewCB->isChecked();
154         restorePB->setEnabled(!in_sync);
155         applyPB->setEnabled(!in_sync);
156         okPB->setEnabled(!in_sync);
157         if (!in_sync)
158                 closePB->setText(qt_("&Cancel"));
159         else
160                 closePB->setText(qt_("&Close"));
161 }
162
163
164 void GuiParagraph::changed()
165 {
166         if (synchronizedViewCB->isChecked())
167                 on_applyPB_clicked();
168 }
169
170
171 void GuiParagraph::on_applyPB_clicked()
172 {
173         applyView();
174 }
175
176
177 void GuiParagraph::on_okPB_clicked()
178 {
179         applyView();
180         hide();
181 }
182
183
184 void GuiParagraph::on_closePB_clicked()
185 {
186         hide();
187 }
188
189
190 void GuiParagraph::on_restorePB_clicked()
191 {
192         updateView();
193 }
194
195
196 void GuiParagraph::applyView()
197 {
198         params_ = params();
199
200         params_.align(getAlignmentFromDialog());
201
202         // get spacing
203         Spacing::Space ls = Spacing::Default;
204         string other;
205         switch (linespacing->currentIndex()) {
206         case 0:
207                 ls = Spacing::Default;
208                 break;
209         case 1:
210                 ls = Spacing::Single;
211                 break;
212         case 2:
213                 ls = Spacing::Onehalf;
214                 break;
215         case 3:
216                 ls = Spacing::Double;
217                 break;
218         case 4:
219                 ls = Spacing::Other;
220                 other = fromqstr(linespacingValue->text());
221                 break;
222         }
223
224         Spacing const spacing(ls, other);
225         params_.spacing(spacing);
226
227         // label width
228         params_.labelWidthString(qstring_to_ucs4(labelWidth->text()));
229         // indendation
230         params_.noindent(!indentCB->isChecked());
231
232         dispatchParams();
233 }
234
235
236 void GuiParagraph::updateView()
237 {
238         on_synchronizedViewCB_toggled();
239
240         ParagraphParameters const & pp = params();
241
242         // label width
243         docstring const & labelwidth = pp.labelWidthString();
244         if (hasLabelwidth()) {
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 const & GuiParagraph::params() const
309 {
310         if (haveMultiParSelection()) {
311                 // FIXME: in case of multi-paragraph selection, it would be nice to
312                 // initialise the parameters that are common to all paragraphs.
313                 static ParagraphParameters empty;
314                 return empty;
315         }
316         return bufferview()->cursor().innerParagraph().params();
317 }
318
319
320 void GuiParagraph::dispatchParams()
321 {
322         ostringstream data;
323         params_.write(data);
324         FuncRequest const fr(getLfun(), data.str());
325         dispatch(fr);
326 }
327
328
329 bool GuiParagraph::haveMultiParSelection() const
330 {
331         Cursor const & cur = bufferview()->cursor();
332         return cur.selection() && cur.selBegin().pit() != cur.selEnd().pit();
333 }
334
335         
336 bool GuiParagraph::canIndent() const
337 {
338         return buffer().params().paragraph_separation
339                 == BufferParams::ParagraphIndentSeparation;
340 }
341
342
343 LyXAlignment GuiParagraph::alignPossible() const
344 {
345         return bufferview()->cursor().innerParagraph().layout().alignpossible;
346 }
347
348
349 LyXAlignment GuiParagraph::alignDefault() const
350 {
351         return bufferview()->cursor().innerParagraph().layout().align;
352 }
353
354
355 bool GuiParagraph::hasLabelwidth() const
356 {
357         Layout layout = bufferview()->cursor().innerParagraph().layout();
358         return (layout.margintype == MARGIN_MANUAL
359                 || layout.latextype == LATEX_BIB_ENVIRONMENT);
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 "moc_GuiParagraph.cpp"