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