1 /****************************************************************************
2 **
3 ** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
4 **
5 ** This file is part of the Edyuk project <http://edyuk.org>
6 **
7 ** This file may be used under the terms of the GNU General Public License
8 ** version 3 as published by the Free Software Foundation and appearing in the
9 ** file GPL.txt included in the packaging of this file.
10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 **
14 ****************************************************************************/
15
16 #include "qformatconfig.h"
17
18 /*!
19 \file qformatconfig.cpp
20 \brief Implementation of the QFormatConfig class.
21
22 \see QFormatConfig
23 */
24
25 #include "qformat.h"
26 #include "qformatscheme.h"
27
28 #include "qeditor.h"
29 #include "qdocument.h"
30
31 #include "qsimplecolorpicker.h"
32
33 #include <QHeaderView>
34 #include <QVBoxLayout>
35 #include <QMessageBox>
36 #include <QTableWidget>
37
38 /*!
39 \ingroup dialogs
40 @{
41
42 \class QFormatConfig
43 \brief A minimalistic, easy to embed, format settings widget.
44
45 */
46
QFormatConfig(QWidget * w)47 QFormatConfig::QFormatConfig(QWidget *w)
48 : QWidget(w), m_autonomous(false), m_currentScheme(0)
49 {
50 setupUi(this);
51
52 m_frame->hide();
53
54 m_table->verticalHeader()->hide();
55
56 m_table->horizontalHeaderItem(1)->setIcon(QIcon(":/bold.png"));
57 m_table->horizontalHeaderItem(2)->setIcon(QIcon(":/italic.png"));
58 m_table->horizontalHeaderItem(3)->setIcon(QIcon(":/underline.png"));
59 //m_table->horizontalHeaderItem(4)->setIcon(QIcon(":/overline.png"));
60 m_table->horizontalHeaderItem(5)->setIcon(QIcon(":/strikeout.png"));
61 //m_table->horizontalHeaderItem(6)->setIcon(QIcon(":/waveUnderline.png"));
62 m_table->horizontalHeaderItem(7)->setIcon(QIcon(":/textcolor.png"));
63 m_table->horizontalHeaderItem(8)->setIcon(QIcon(":/fillcolor.png"));
64 m_table->horizontalHeaderItem(9)->setIcon(QIcon(":/strokecolor.png"));
65
66 connect(m_table, SIGNAL( itemSelectionChanged() ),
67 m_table, SLOT ( clearSelection() ) );
68
69 }
70
71 /*!
72 \brief run-time translation entry point
73 */
retranslate()74 void QFormatConfig::retranslate()
75 {
76 retranslateUi(this);
77 }
78
79 /*!
80 \return Whether the format config widget is in "autonomous" mode
81 */
isAutonomous() const82 bool QFormatConfig::isAutonomous() const
83 {
84 return m_autonomous;
85 }
86
87 /*!
88 \brief Turn on "autonomous" mode
89
90 When the format config widget is autonomous it will automatically
91 check for changes upon hide event and ask the user whether he wishes
92 to commit them.
93 */
setAutonomous(bool y)94 void QFormatConfig::setAutonomous(bool y)
95 {
96 m_autonomous = y;
97 }
98
99 /*!
100 \brief Check whether there are unsaved in the widget
101 */
hasUnsavedChanges() const102 bool QFormatConfig::hasUnsavedChanges() const
103 {
104 return modifiedFormats().count();
105 }
106
107 /*!
108 \return the list of format schemes this config widget "manages"
109 */
schemes() const110 QList<QFormatScheme*> QFormatConfig::schemes() const
111 {
112 return m_schemes;
113 }
114
115 /*!
116 \brief Add a format scheme to the config widget
117
118 Users will be able to edit that scheme (switching among schemes using
119 a combobox if several schemes are added to the widget)
120 */
addScheme(const QString & name,QFormatScheme * scheme)121 void QFormatConfig::addScheme(const QString& name, QFormatScheme *scheme)
122 {
123 m_schemes << scheme;
124
125 m_selector->addItem(name);
126
127 if ( m_schemes.count() > 1 && m_schemes.contains(m_currentScheme) )
128 {
129 // show the scheme selector
130 m_frame->show();
131 }
132
133 if ( !m_currentScheme )
134 setCurrentScheme(scheme);
135 }
136
137 /*!
138 \brief Remove a scheme from the config widget
139
140 \note No attempt is made to commit unsaved changes
141 */
removeScheme(QFormatScheme * s)142 void QFormatConfig::removeScheme(QFormatScheme *s)
143 {
144 if ( m_currentScheme == s )
145 {
146 m_currentScheme = 0;
147 }
148
149 for ( int i = 0; i < m_schemes.count(); ++i )
150 {
151 if ( m_schemes.at(i) == s )
152 {
153 m_selector->removeItem(i);
154 m_schemes.removeAt(i);
155 }
156 }
157
158 if ( m_schemes.count() <= 1 )
159 {
160 // hide the scheme selector
161 m_frame->hide();
162 }
163 }
164
165 /*!
166 \brief Enforce the currently edited scheme
167
168 \note It is possible to pass a scheme not previously added to the widget,
169 but it really isn't recommended.
170 */
setCurrentScheme(QFormatScheme * s)171 void QFormatConfig::setCurrentScheme(QFormatScheme *s)
172 {
173 int idx = m_schemes.indexOf(s);
174
175 if ( idx != -1 )
176 {
177 m_currentScheme = s;
178
179 // update table widget
180 cancel();
181 } else {
182 m_selector->setCurrentIndex(idx);
183 }
184 }
185
186 /*!
187 \brief Apply changes made to the currently edited scheme, if any
188 */
apply()189 void QFormatConfig::apply()
190 {
191 if ( m_currentScheme )
192 {
193 const int n = m_currentScheme->formatCount();
194
195 m_table->setRowCount(n);
196
197 for ( int i = 0 ; i < n; ++i )
198 {
199 QString fid = m_currentScheme->id(i);
200 QFormat& fmt = m_currentScheme->formatRef(i);
201
202 QTableWidgetItem *item;
203
204 item = m_table->item(i, 1);
205 fmt.weight = item->checkState() == Qt::Checked ? QFont::Bold : QFont::Normal;
206
207 item = m_table->item(i, 2);
208 fmt.italic = item->checkState() == Qt::Checked;
209
210 item = m_table->item(i, 3);
211 fmt.underline = item->checkState() == Qt::Checked;
212
213 item = m_table->item(i, 4);
214 fmt.overline = item->checkState() == Qt::Checked;
215
216 item = m_table->item(i, 5);
217 fmt.strikeout = item->checkState() == Qt::Checked;
218
219 item = m_table->item(i, 6);
220 fmt.waveUnderline = item->checkState() == Qt::Checked;
221
222 QSimpleColorPicker *cp;
223
224 cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 7));
225 if ( cp )
226 fmt.foreground = cp->color();
227
228 cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 8));
229 if ( cp )
230 fmt.background = cp->color();
231
232 cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 9));
233 if ( cp )
234 fmt.linescolor = cp->color();
235
236 }
237
238 // TODO : save scheme and update editors
239
240 // this will only save schemes loaded from an existing file
241 m_currentScheme->save();
242
243 if ( m_autonomous )
244 {
245 QList<QEditor*> editors = QEditor::editors();
246
247 foreach ( QEditor *e, editors )
248 {
249 if ( e->document()->formatScheme() == m_currentScheme )
250 e->viewport()->update();
251 }
252 }
253 }
254 }
255
256 /*!
257 \brief Reset the subcontrols to reflect the data of the format scheme being edited
258
259 The name can be a bit misleading at first, it has been chosen
260 because it directly maps to the effect a "cancel" button would
261 have on the widget
262 */
cancel()263 void QFormatConfig::cancel()
264 {
265 m_table->clearContents();
266
267 if ( m_currentScheme )
268 {
269 const int n = m_currentScheme->formatCount();
270
271 m_table->setRowCount(n);
272
273 for ( int i = 0 ; i < n; ++i )
274 {
275 QString fid = m_currentScheme->id(i);
276 const QFormat& fmt = m_currentScheme->formatRef(i);
277
278 QTableWidgetItem *item;
279
280 item = new QTableWidgetItem(fid);
281 item->setFlags(Qt::ItemIsEnabled);
282 m_table->setItem(i, 0, item);
283
284 item = new QTableWidgetItem;
285 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
286 item->setCheckState(fmt.weight == QFont::Bold ? Qt::Checked : Qt::Unchecked);
287 item->setToolTip(tr("Bold"));
288 m_table->setItem(i, 1, item);
289
290 item = new QTableWidgetItem;
291 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
292 item->setCheckState(fmt.italic ? Qt::Checked : Qt::Unchecked);
293 item->setToolTip(tr("Italic"));
294 m_table->setItem(i, 2, item);
295
296 item = new QTableWidgetItem;
297 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
298 item->setCheckState(fmt.underline ? Qt::Checked : Qt::Unchecked);
299 item->setToolTip(tr("Underline"));
300 m_table->setItem(i, 3, item);
301
302 item = new QTableWidgetItem;
303 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
304 item->setCheckState(fmt.overline ? Qt::Checked : Qt::Unchecked);
305 item->setToolTip(tr("Overline"));
306 m_table->setItem(i, 4, item);
307
308 item = new QTableWidgetItem;
309 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
310 item->setCheckState(fmt.strikeout ? Qt::Checked : Qt::Unchecked);
311 item->setToolTip(tr("Strikeout"));
312 m_table->setItem(i, 5, item);
313
314 item = new QTableWidgetItem;
315 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
316 item->setCheckState(fmt.waveUnderline ? Qt::Checked : Qt::Unchecked);
317 item->setToolTip(tr("Wave underline"));
318 m_table->setItem(i, 6, item);
319
320 m_table->setCellWidget(i, 7, new QSimpleColorPicker(fmt.foreground));
321 m_table->cellWidget(i, 7)->setToolTip(tr("Text color (aka foreground)"));
322 //m_table->cellWidget(i, 7)->setMaximumSize(22, 22);
323
324 m_table->setCellWidget(i, 8, new QSimpleColorPicker(fmt.background));
325 m_table->cellWidget(i, 8)->setToolTip(tr("Background color"));
326 //m_table->cellWidget(i, 8)->setMaximumSize(22, 22);
327
328 m_table->setCellWidget(i, 9, new QSimpleColorPicker(fmt.linescolor));
329 m_table->cellWidget(i, 9)->setToolTip(tr("Lines color (used by all lines formatting : underline, overline, ...)"));
330 //m_table->cellWidget(i, 9)->setMaximumSize(22, 22);
331 }
332 }
333
334 m_table->resizeColumnsToContents();
335 }
336
337 /*!
338 \brief Restore default values for all subcontrols
339
340 \note The widgets are changed but these changes are NOT applied.
341 */
restore()342 void QFormatConfig::restore()
343 {
344 // restoring what? this is only provided for API consistency and in case
345 // (very unlikely to ever happen) design changes make restore() a sensible
346 // thing to do on format schemes
347 }
348
modifiedFormats() const349 QList<int> QFormatConfig::modifiedFormats() const
350 {
351 QList<int> hasModif;
352
353 if ( m_currentScheme )
354 {
355 const int n = m_currentScheme->formatCount();
356
357 m_table->setRowCount(n);
358
359 for ( int i = 0 ; i < n; ++i )
360 {
361 QString fid = m_currentScheme->id(i);
362 QFormat& fmt = m_currentScheme->formatRef(i);
363
364 QTableWidgetItem *item;
365
366 item = m_table->item(i, 1);
367 if ( fmt.weight != (item->checkState() == Qt::Checked ? QFont::Bold : QFont::Normal) )
368 {
369 hasModif << i;
370 continue;
371 }
372
373 item = m_table->item(i, 2);
374 if ( fmt.italic != (item->checkState() == Qt::Checked) )
375 {
376 hasModif << i;
377 continue;
378 }
379
380 item = m_table->item(i, 3);
381 if ( fmt.underline != (item->checkState() == Qt::Checked) )
382 {
383 hasModif << i;
384 continue;
385 }
386
387 item = m_table->item(i, 4);
388 if ( fmt.overline != (item->checkState() == Qt::Checked) )
389 {
390 hasModif << i;
391 continue;
392 }
393
394 item = m_table->item(i, 5);
395 if ( fmt.strikeout != (item->checkState() == Qt::Checked) )
396 {
397 hasModif << i;
398 continue;
399 }
400
401 item = m_table->item(i, 6);
402 if ( fmt.waveUnderline != (item->checkState() == Qt::Checked) )
403 {
404 hasModif << i;
405 continue;
406 }
407
408 QSimpleColorPicker *cp;
409
410 cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 7));
411 if ( cp && fmt.foreground != cp->color() )
412 {
413 hasModif << i;
414 continue;
415 }
416
417 cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 8));
418 if ( cp && fmt.background != cp->color() )
419 {
420 hasModif << i;
421 continue;
422 }
423
424 cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 9));
425 if ( cp && fmt.linescolor != cp->color() )
426 {
427 hasModif << i;
428 continue;
429 }
430 }
431 }
432
433 return hasModif;
434 }
435
hideEvent(QHideEvent * e)436 void QFormatConfig::hideEvent(QHideEvent *e)
437 {
438 Q_UNUSED(e)
439
440 if ( !m_autonomous )
441 return;
442
443 QList<int> hasModif = modifiedFormats();
444
445 if ( hasModif.count() )
446 {
447 // TODO : provide custom widget to allow user to select which items should be saved?
448 int ret = QMessageBox::warning(
449 0,
450 tr("Unsaved changes"),
451 tr("There are unsaved changes in this format scheme.\nDo you want them to be saved?"),
452 QMessageBox::Save | QMessageBox::Discard
453 );
454
455 if ( ret == QMessageBox::Save )
456 {
457 apply();
458 } else {
459 cancel();
460 }
461 }
462 }
463
on_m_selector_currentIndexChanged(int idx)464 void QFormatConfig::on_m_selector_currentIndexChanged(int idx)
465 {
466 QList<int> hasModif = modifiedFormats();
467
468 if ( hasModif.count() )
469 {
470 // TODO : provide custom widget to allow user to select which items should be saved?
471 int ret = QMessageBox::warning(
472 0,
473 tr("Unsaved changes"),
474 tr("There are unsaved changes in this format scheme.\nDo you want them to be saved?"),
475 QMessageBox::Save | QMessageBox::Discard
476 );
477
478 if ( ret == QMessageBox::Save )
479 {
480 apply();
481 } else {
482 cancel();
483 }
484 }
485
486 m_currentScheme = idx >= 0 && idx < m_schemes.count() ? m_schemes.at(idx) : 0;
487
488 cancel();
489 }
490
491 /*! @} */
492