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