1 /* This file is part of the KDE project
2  * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 // clazy:excludeall=qstring-arg
21 #include "KoPageLayoutWidget.h"
22 
23 #include <ui_KoPageLayoutWidget.h>
24 
25 #include <KoUnit.h>
26 
27 #include <QButtonGroup>
28 
29 class Q_DECL_HIDDEN KoPageLayoutWidget::Private
30 {
31 public:
32     Ui::KoPageLayoutWidget widget;
33     KoPageLayout pageLayout;
34     KoUnit unit;
35 
36     QButtonGroup *orientationGroup;
37     bool marginsEnabled;
38     bool allowSignals;
39 };
40 
41 
KoPageLayoutWidget(QWidget * parent,const KoPageLayout & layout)42 KoPageLayoutWidget::KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout)
43     : QWidget(parent)
44     , d(new Private)
45 {
46     d->widget.setupUi(this);
47 
48     d->pageLayout = layout;
49     d->marginsEnabled = true;
50     d->allowSignals = true;
51     d->orientationGroup = new QButtonGroup(this);
52     d->orientationGroup->addButton(d->widget.portrait, KoPageFormat::Portrait);
53     d->orientationGroup->addButton(d->widget.landscape, KoPageFormat::Landscape);
54 
55     QButtonGroup *group2 = new QButtonGroup(this);
56     group2->addButton(d->widget.singleSided);
57     group2->addButton(d->widget.facingPages);
58     // the two sets of labels we use might have different lengths; make sure this does not create a 'jumping' ui
59     d->widget.facingPages->setChecked(true);
60     facingPagesChanged();
61     int width = qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width());
62     d->widget.singleSided->setChecked(true);
63     facingPagesChanged();
64     width = qMax(width, qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width()));
65     d->widget.leftLabel->setMinimumSize(QSize(width, 5));
66 
67     d->widget.units->addItems(KoUnit::listOfUnitNameForUi(KoUnit::HidePixel));
68     d->widget.sizes->addItems(KoPageFormat::localizedPageFormatNames());
69     setPageSpread(false);
70 
71     connect(d->widget.sizes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &KoPageLayoutWidget::sizeChanged);
72     connect(d->widget.units, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &KoPageLayoutWidget::slotUnitChanged);
73     connect(group2, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &KoPageLayoutWidget::facingPagesChanged);
74     connect(d->orientationGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &KoPageLayoutWidget::orientationChanged);
75     connect(d->widget.width, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged);
76     connect(d->widget.height, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged);
77     connect(d->widget.topMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged);
78     connect(d->widget.bottomMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged);
79     connect(d->widget.bindingEdgeMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged);
80     connect(d->widget.pageEdgeMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged);
81     connect(d->widget.width, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged);
82     connect(d->widget.height, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged);
83 
84     setUnit(KoUnit(KoUnit::Millimeter));
85     setPageLayout(layout);
86     if (layout.format == 0) // make sure we always call this during startup, even if the A3 (index=0) was chosen
87         sizeChanged(layout.format);
88 
89     showTextDirection(false);
90     /* disable advanced page layout features by default */
91     d->widget.facingPageLabel->setVisible(false);
92     d->widget.facingPages->setVisible(false);
93     d->widget.singleSided->setVisible(false);
94     d->widget.stylesLabel->setVisible(false);
95     d->widget.pageStyle->setVisible(false);
96 }
97 
~KoPageLayoutWidget()98 KoPageLayoutWidget::~KoPageLayoutWidget()
99 {
100     delete d;
101 }
102 
pageLayout() const103 KoPageLayout KoPageLayoutWidget::pageLayout() const
104 {
105     return d->pageLayout;
106 }
107 
sizeChanged(int row)108 void KoPageLayoutWidget::sizeChanged(int row)
109 {
110     if (row < 0) return;
111     if (! d->allowSignals) return;
112     d->allowSignals = false;
113     d->pageLayout.format = static_cast<KoPageFormat::Format> (row);
114     bool custom =  d->pageLayout.format == KoPageFormat::CustomSize;
115     d->widget.width->setEnabled(custom);
116     d->widget.height->setEnabled(custom);
117 
118     if (!custom) {
119         d->pageLayout.width = MM_TO_POINT(KoPageFormat::width(d->pageLayout.format, d->pageLayout.orientation));
120         d->pageLayout.height = MM_TO_POINT(KoPageFormat::height(d->pageLayout.format, d->pageLayout.orientation));
121         if (d->widget.facingPages->isChecked()) // is pagespread
122             d->pageLayout.width *= 2;
123     }
124 
125     d->widget.width->changeValue(d->pageLayout.width);
126     d->widget.height->changeValue(d->pageLayout.height);
127 
128     emit layoutChanged(d->pageLayout);
129     d->allowSignals = true;
130 }
131 
slotUnitChanged(int row)132 void KoPageLayoutWidget::slotUnitChanged(int row)
133 {
134     setUnit(KoUnit::fromListForUi(row, KoUnit::HidePixel));
135 }
136 
setUnit(const KoUnit & unit)137 void KoPageLayoutWidget::setUnit(const KoUnit &unit)
138 {
139     if (d->unit == unit)
140         return;
141     d->unit = unit;
142 
143     d->widget.width->setUnit(unit);
144     d->widget.height->setUnit(unit);
145     d->widget.topMargin->setUnit(unit);
146     d->widget.bottomMargin->setUnit(unit);
147     d->widget.bindingEdgeMargin->setUnit(unit);
148     d->widget.pageEdgeMargin->setUnit(unit);
149     d->widget.units->setCurrentIndex(unit.indexInListForUi(KoUnit::HidePixel));
150 
151     emit unitChanged(d->unit);
152 }
153 
setPageLayout(const KoPageLayout & layout)154 void KoPageLayoutWidget::setPageLayout(const KoPageLayout &layout)
155 {
156     if (! d->allowSignals) return;
157     d->allowSignals = false;
158     d->pageLayout = layout;
159 
160     Q_ASSERT(d->orientationGroup->button(layout.orientation));
161     d->orientationGroup->button(layout.orientation)->setChecked(true);
162     if (layout.bindingSide >= 0 && layout.pageEdge >= 0) {
163         d->widget.facingPages->setChecked(true);
164         d->widget.bindingEdgeMargin->changeValue(layout.bindingSide);
165         d->widget.pageEdgeMargin->changeValue(layout.pageEdge);
166         d->pageLayout.leftMargin = -1;
167         d->pageLayout.rightMargin = -1;
168     }
169     else {
170         d->widget.singleSided->setChecked(true);
171         d->widget.bindingEdgeMargin->changeValue(layout.leftMargin);
172         d->widget.pageEdgeMargin->changeValue(layout.rightMargin);
173         d->pageLayout.pageEdge = -1;
174         d->pageLayout.bindingSide = -1;
175     }
176     facingPagesChanged();
177 
178     d->widget.topMargin->changeValue(layout.topMargin);
179     d->widget.bottomMargin->changeValue(layout.bottomMargin);
180     d->allowSignals = true;
181     d->widget.sizes->setCurrentIndex(layout.format); // calls sizeChanged()
182 }
183 
facingPagesChanged()184 void KoPageLayoutWidget::facingPagesChanged()
185 {
186     if (! d->allowSignals) return;
187     d->allowSignals = false;
188     if (d->widget.singleSided->isChecked()) {
189         d->widget.leftLabel->setText(i18n("Left Edge:"));
190         d->widget.rightLabel->setText(i18n("Right Edge:"));
191     }
192     else {
193         d->widget.leftLabel->setText(i18n("Binding Edge:"));
194         d->widget.rightLabel->setText(i18n("Page Edge:"));
195     }
196     d->allowSignals = true;
197     marginsChanged();
198     sizeChanged(d->widget.sizes->currentIndex());
199 }
200 
marginsChanged()201 void KoPageLayoutWidget::marginsChanged()
202 {
203     if (! d->allowSignals) return;
204     d->allowSignals = false;
205     d->pageLayout.leftMargin = -1;
206     d->pageLayout.rightMargin = -1;
207     d->pageLayout.bindingSide = -1;
208     d->pageLayout.pageEdge = -1;
209     d->pageLayout.topMargin = d->marginsEnabled?d->widget.topMargin->value():0;
210     d->pageLayout.bottomMargin = d->marginsEnabled?d->widget.bottomMargin->value():0;
211     qreal left = d->marginsEnabled?d->widget.bindingEdgeMargin->value():0;
212     qreal right = d->marginsEnabled?d->widget.pageEdgeMargin->value():0;
213     if (left + right > d->pageLayout.width - 10) {
214         // make sure the actual text area is never smaller than 10 points.
215         qreal diff = d->pageLayout.width - 10 - left - right;
216         left = qMin(d->pageLayout.width - 10, qMax(qreal(0.0), left - diff / qreal(2.0)));
217         right = qMax(qreal(0.0), right - d->pageLayout.width - 10 - left);
218     }
219 
220     if (d->widget.singleSided->isChecked()) {
221         d->pageLayout.leftMargin  = left;
222         d->pageLayout.rightMargin = right;
223     }
224     else {
225         d->pageLayout.bindingSide = left;
226         d->pageLayout.pageEdge = right;
227     }
228     // debugWidgets << "  " << d->pageLayout.left <<"|"<< d->pageLayout.bindingSide << "," <<
229     //    d->pageLayout.right << "|"<< d->pageLayout.pageEdge;
230     emit layoutChanged(d->pageLayout);
231     d->allowSignals = true;
232 }
233 
setTextAreaAvailable(bool available)234 void KoPageLayoutWidget::setTextAreaAvailable(bool available)
235 {
236     d->marginsEnabled = available;
237     d->widget.margins->setEnabled(available);
238     marginsChanged();
239 }
240 
optionsChanged()241 void KoPageLayoutWidget::optionsChanged()
242 {
243     if (! d->allowSignals) return;
244     if (d->widget.sizes->currentIndex() == KoPageFormat::CustomSize) {
245         d->pageLayout.width = d->widget.width->value();
246         d->pageLayout.height = d->widget.height->value();
247     } else
248         sizeChanged(d->widget.sizes->currentIndex());
249 
250     marginsChanged();
251 }
252 
orientationChanged()253 void KoPageLayoutWidget::orientationChanged()
254 {
255     if (! d->allowSignals) return;
256     d->allowSignals = false;
257     d->pageLayout.orientation = d->widget.landscape->isChecked() ? KoPageFormat::Landscape : KoPageFormat::Portrait;
258 
259     qreal x = d->widget.height->value();
260     d->widget.height->changeValue(d->widget.width->value());
261     d->widget.width->changeValue(x);
262 
263     d->allowSignals = true;
264     optionsChanged();
265 }
266 
showUnitchooser(bool on)267 void KoPageLayoutWidget::showUnitchooser(bool on) {
268     d->widget.units->setVisible(on);
269     d->widget.unitsLabel->setVisible(on);
270 }
271 
showPageSpread(bool on)272 void KoPageLayoutWidget::showPageSpread(bool on)
273 {
274     d->widget.facingPageLabel->setVisible(on);
275     d->widget.singleSided->setVisible(on);
276     d->widget.facingPages->setVisible(on);
277 }
278 
setPageSpread(bool pageSpread)279 void KoPageLayoutWidget::setPageSpread(bool pageSpread)
280 {
281     if (pageSpread)
282         d->widget.facingPages->setChecked(true);
283     else
284         d->widget.singleSided->setChecked(true);
285 }
286 
setApplyToDocument(bool apply)287 void KoPageLayoutWidget::setApplyToDocument(bool apply)
288 {
289     if (apply) {
290         d->widget.facingPageLabel->setText(i18n("Facing Pages:"));
291         d->widget.facingPages->setText(i18n("Facing pages"));
292     }
293     else {
294         d->widget.facingPageLabel->setText(i18n("Page Layout:"));
295         d->widget.facingPages->setText(i18n("Page spread"));
296     }
297 }
298 
showTextDirection(bool on)299 void KoPageLayoutWidget::showTextDirection(bool on)
300 {
301     d->widget.directionLabel->setVisible(on);
302     d->widget.textDirection->setVisible(on);
303 }
304 /*
305 void KoPageLayoutWidget::setTextDirection(KoText::Direction direction)
306 {
307     int index = 0;
308     switch(direction) {
309     case KoText::LeftRightTopBottom:
310         index = 1;
311         break;
312     case KoText::RightLeftTopBottom:
313         index = 2;
314         break;
315     case KoText::TopBottomRightLeft: // unused for now.
316     case KoText::InheritDirection:
317     case KoText::AutoDirection:
318         index = 0;
319     case KoText::TopBottomLeftRight:
320         ; // unhandled, because it actually doesn't exist in real-world writing systems.
321           // Boustrophedon would be interesting to implement, though
322     }
323     d->widget.textDirection->setCurrentIndex(index);
324 }
325 
326 KoText::Direction KoPageLayoutWidget::textDirection() const
327 {
328     switch(d->widget.textDirection->currentIndex()) {
329     case 1: return KoText::LeftRightTopBottom;
330     case 2: return KoText::RightLeftTopBottom;
331     default:
332     case 0: return KoText::AutoDirection;
333     }
334 }
335 */
showPageStyles(bool on)336 void KoPageLayoutWidget::showPageStyles(bool on)
337 {
338     d->widget.stylesLabel->setVisible(on);
339     d->widget.pageStyle->setVisible(on);
340 }
341 
setPageStyles(const QStringList & styles)342 void KoPageLayoutWidget::setPageStyles(const QStringList &styles)
343 {
344     d->widget.pageStyle->clear();
345     d->widget.pageStyle->addItems(styles);
346 }
347 
currentPageStyle() const348 QString KoPageLayoutWidget::currentPageStyle() const
349 {
350     return d->widget.pageStyle->currentText();
351 }
352